Skip to content

Commit

Permalink
Merge pull request #3599 from wireapp/outlook-integration-helm-chart
Browse files Browse the repository at this point in the history
Outlook integration helm chart
  • Loading branch information
Veki301 committed Sep 22, 2023
2 parents b6f9622 + 2c53363 commit 2ed0a3c
Show file tree
Hide file tree
Showing 9 changed files with 440 additions and 0 deletions.
4 changes: 4 additions & 0 deletions charts/outlook-addin/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v1
name: outlook-addin
version: 4.38.0
description: Helm chart for outlook addin for Wire
191 changes: 191 additions & 0 deletions charts/outlook-addin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# How to install Outlook AddIn for Wire-Server

WIP: Some of these configurations are subject to change down the line. This documentation will be updated accordingly as they happen.

This document assumes you already have an instance of wire-server running. If you don't, follow this [documentation](https://github.com/wireapp/wire-server-deploy/blob/master/offline/docs.md)

## Set up OAuth with wire-server

To use OAuth, first you will need to enable it by editing `values/wire-server/values.yaml` as follows:

```
brig:
# ...
config:
# ...
optSettings:
# ...
setOAuthEnabled: true
```

Then you will need to generate a key using "OKP" (Octet Key Pair) and the "Ed25519" curve with OpenSSL that will be used as JWK (JSON Web Key) in the wire-server helm chart. This key will be used to sign and verify [OAuth](https://docs.wire.com/developer/reference/oauth.html#setting-up-public-and-private-keys) access tokens.

```
openssl genpkey -algorithm Ed25519 -out private_key.pem
```

You can find a `generate_jwk.py` in this chart which you can use to generate the JWK in JSON format that can be used in your wire-server helm chart. Use it in `brig` and `nginz` namespaces in `values/wire-server/secrets.yaml` like shown below.

```
brig:
secrets:
oauthJwkKeyPair: |
{
"kty": "OKP",
"crv": "Ed25519",
"x": "...",
"d": "...",
"kid": "..."
}
```

```
# values.yaml or secrets.yaml
nginz:
secrets:
oAuth:
publicKeys: |
{
"kty": "OKP",
"crv": "Ed25519",
"x": "...",
"kid": "..."
}
```

Now redeploy wire-server chart:

```
d helm upgrade --install wire-server charts/wire-server --values values/wire-server/values.yaml --values/wire-server/secrets.yaml
```

## Outlook integration feature flag

By default, outlook addin as a feature is disabled for all teams. To change this make the following changes in your configuration in `galley` namespace:

```
galley:
config:
# ...
settings:
# ...
featureFlags:
# ...
outlookCalIntegration:
defaults:
status: enabled
lockStatus: unlocked
```

Redeploy wire-server for these changes to take effect.

NOTE: As of the time of writing `outlookCalIntegration` is not a typo! (at least not in this documentation)

If you have an existing team in your wire-server that did not have this feature flag enabled prior to this. You will need to enable that feature flag through [Backoffice API](https://github.com/wireapp/wire-server/tree/05778a2b14ac5aaffca937d6e2cdd9b7b5f3106d/charts/backoffice).

NOTE: As of the time of writing Backoffice API endpoint for enabling this feature flag is not working as intended so please follow this manual on how to do it with curl on the machine wire-server is running on.

### How to manually enable outlookCalIntegration feature flag for a team

You will need your `teamId` (you can find it in TeamSettings under Customization tab).
List all your pods in your Kubernetes cluster with:

```
d kubectl get pods -owide
```

Copy the name of one of your galley pods and run:

```
d kubectl exec -it galley_pod_name /bin/bash
```

In the new terminal type:

```
curl -v -XPATCH 'http://localhost:8080/i/teams/your_teamID/features/outlookCalIntegration' -H 'content-type: application/json;charset=utf-8' -d '{"status": "enabled", "lockStatus": "unlocked"}'
```

Do this for all the teams you want to enable the feature for.

## Create new client service for OAuth in Brig

List all your pods in your Kubernetes cluster with:

```
d kubectl get pods -owide
```

Copy the name of one of your brig pods and run:

```
d kubectl exec -it brig_pod_name /bin/bash
```

In the new terminal type:

```
curl -s -X POST localhost:8080/i/oauth/clients \
-H "Content-Type: application/json" \
-d '{
"application_name":"Wire Microsoft Outlook Calendar Add-in",
"redirect_url":"https://outlook.example.com/callback.html"
}'
```

You will get back a response in JSON format that should look like:

```
{"client_id":"b2b3...","client_secret":"9ee60..."}
```

Write down your client_id as it will be needed later.

## Deploying Wire Outlook AddIn

Create a new `values.yaml` file in `values/outlook-addin` directory (create the directory too if missing).
Append the following configuration (change the example.com with your domain).

```
host: "outlook.example.com" # this entry has to be without https://!!!
wireApiBaseUrl: "https://nginz-https.example.com"
wireAuthorizationEndpoint: "https://webapp.example.com/auth"
clientId: ""
```

As of the time of writing nginz used by wire-server is not set up to whitelist outlook subdomain for CORS requests. So please edit `charts/wire-server/charts/nginz/values.yaml` and find under `nginx_conf`:

```
allowlisted_origins:
- webapp
- teams
- account
- outlook # add outlook entry so your addin doesnt get CORS blocked
```

### Certificates

If you are using cert-manager just make the following configuration in values.yaml:

```
tls:
issuerRef:
name: letsencrypt-http01 # letsencrypt-http01 is a default config in wire-server, change if needed in your instance
```

Now deploy outlook addin chart with:

```
d helm upgrade --install outlook-addin charts/outlook-addin --values values/outlook-addin/values.yaml
```

If you are using your own provided certificates, deploy the addin with this command:

```
d helm upgrade --install outlook-addin charts/outlook-addin --values values/outlook-addin/values.yaml --set-file tls.crt=/path/to/tls.crt --set-file tls.key=/path/to/tls.key
```

## Install Wire AddIn in Microsoft Outlook

After deploying `outlook-addin` you will be able to find `manifest.xml` file on https://outlook.example.com/manifest.xml which you can use to install the addin in your outlook. You can find instructions and screenshots how to do it [here](https://github.com/tlebon/outlook-addin/blob/staging/README.md#how-to-install-the-add-in-in-ms-outlook).
NOTE: Links in the outlined documents are hardcoded for a testing/prod environment, any reference to zinfra.io or wire.com in it should be treated as example.com.
23 changes: 23 additions & 0 deletions charts/outlook-addin/generate_jwk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import json
from jwcrypto import jwk
import base64

def pem_to_jwk(pem_key, is_private=True):
key = jwk.JWK.from_pem(pem_key)
if is_private:
key_dict = key.export(as_dict=True, private_key=True)
else:
key_dict = key.export(as_dict=True, private_key=False)
return key_dict

def convert_to_pem(base64_key):
pem_key = base64.b64decode(base64_key)
return pem_key

with open("private_key.pem", "rb") as f:
private_key_pem = f.read()
private_key_b64 = base64.b64encode(private_key_pem).decode('utf-8')
private_jwk = pem_to_jwk(convert_to_pem(private_key_b64), is_private=True)

print("Private JWK:")
print(json.dumps(private_jwk, indent=2))
82 changes: 82 additions & 0 deletions charts/outlook-addin/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "outlook.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "outlook.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "outlook.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "outlook.labels" -}}
helm.sh/chart: {{ include "outlook.chart" . }}
{{ include "outlook.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "outlook.selectorLabels" -}}
app.kubernetes.io/name: {{ include "outlook.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/* Allow KubeVersion to be overridden. */}}
{{- define "kubeVersion" -}}
{{- default .Capabilities.KubeVersion.Version .Values.kubeVersionOverride -}}
{{- end -}}

{{/* Get Ingress API Version */}}
{{- define "ingress.apiVersion" -}}
{{- if and (.Capabilities.APIVersions.Has "networking.k8s.io/v1") (semverCompare ">= 1.19-0" (include "kubeVersion" .)) -}}
{{- print "networking.k8s.io/v1" -}}
{{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
{{- print "networking.k8s.io/v1beta1" -}}
{{- else -}}
{{- print "extensions/v1beta1" -}}
{{- end -}}
{{- end -}}

{{/* Check Ingress stability */}}
{{- define "ingress.isStable" -}}
{{- eq (include "ingress.apiVersion" .) "networking.k8s.io/v1" -}}
{{- end -}}

{{/* Check Ingress supports pathType */}}
{{/* pathType was added to networking.k8s.io/v1beta1 in Kubernetes 1.18 */}}
{{- define "ingress.supportsPathType" -}}
{{- or (eq (include "ingress.isStable" .) "true") (and (eq (include "ingress.apiVersion" .) "networking.k8s.io/v1beta1") (semverCompare ">= 1.18-0" (include "kubeVersion" .))) -}}
{{- end -}}

{{- define "ingress.FieldNotAnnotation" -}}
{{- (semverCompare ">= 1.27-0" (include "kubeVersion" .)) -}}
{{- end -}}
42 changes: 42 additions & 0 deletions charts/outlook-addin/templates/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "outlook.fullname" . }}
labels:
{{- include "outlook.labels" . | nindent 4 }}
spec:
replicas: 3
selector:
matchLabels:
app: {{ include "outlook.fullname" . }}
template:
metadata:
labels:
app: {{ include "outlook.fullname" . }}
spec:
containers:
- name: {{ include "outlook.fullname" . }}
image: {{ .Values.containerImage }}
ports:
- name: http
containerPort: 80
env:
- name: BASE_URL
value: "https://{{ .Values.host }}"
- name: CLIENT_ID
value: "{{ .Values.clientId }}"
- name: WIRE_API_BASE_URL
value: "{{ .Values.wireApiBaseUrl }}"
- name: WIRE_AUTHORIZATION_ENDPOINT
value: "{{ .Values.wireAuthorizationEndpoint }}"
- name: SUPPORT_URL
value: "{{ .Values.supportUrl }}"
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
34 changes: 34 additions & 0 deletions charts/outlook-addin/templates/ingress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{{- $apiIsStable := eq (include "ingress.isStable" .) "true" -}}
{{- $ingressFieldNotAnnotation := eq (include "ingress.FieldNotAnnotation" .) "true" -}}
{{- $ingressSupportsPathType := eq (include "ingress.supportsPathType" .) "true" -}}
apiVersion: {{ include "ingress.apiVersion" . }}
kind: Ingress
metadata:
name: "{{ include "outlook.fullname" . }}"
labels:
{{- include "outlook.labels" . | nindent 4 }}
annotations:
{{- if not $ingressFieldNotAnnotation }}
kubernetes.io/ingress.class: "{{ .Values.config.ingressClass }}"
{{- end }}
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "{{ required "Must specify allowOrigin" .Values.allowOrigin }}"
spec:
{{- if $ingressFieldNotAnnotation }}
ingressClassName: "{{ .Values.config.ingressClass }}"
{{- end }}
tls:
- hosts:
- "{{ .Values.host }}"
secretName: "{{ include "outlook.fullname" . }}"
rules:
- host: "{{ .Values.host }}"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ include "outlook.fullname" . }}
port:
number: 8080
Loading

0 comments on commit 2ed0a3c

Please sign in to comment.