From 5284c8c32b2b32d71207b0b33f3676b7a9064b6e Mon Sep 17 00:00:00 2001 From: Bobby DeSimone Date: Fri, 29 Mar 2019 08:35:31 -0700 Subject: [PATCH] deployment: update helm and add quick-start docs (#75) - adds quick-start documentation for using helm - update helm deployment charts to match outstanding official charts repo. --- docs/.vuepress/config.js | 2 +- docs/guide/helm.md | 72 +++++++++++ docs/guide/kubernetes.md | 5 - helm/Chart.yaml | 4 +- helm/OWNERS | 5 + helm/README.md | 66 +++++++++- helm/templates/NOTES.txt | 67 ++++++++++ helm/templates/_helpers.tpl | 21 +++ helm/templates/authenticate-deployment.yaml | 62 ++++----- helm/templates/authenticate-service.yaml | 11 +- helm/templates/authorize-deployment.yaml | 47 +++---- helm/templates/authorize-service.yaml | 11 +- helm/templates/configmap.yaml | 2 + helm/templates/ingress.yaml | 60 +++++---- helm/templates/proxy-deployment.yaml | 62 +++++---- helm/templates/proxy-service.yaml | 11 +- helm/templates/secret.yaml | 39 +++++- helm/templates/tls-secrets.yaml | 8 +- helm/values.yaml | 136 +++++++++++--------- scripts/helm_gke.sh | 41 +++--- 20 files changed, 484 insertions(+), 248 deletions(-) create mode 100644 docs/guide/helm.md create mode 100644 helm/OWNERS create mode 100644 helm/templates/NOTES.txt diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 5f9c30dbc..c24500378 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -30,7 +30,7 @@ function guideSidebar(title) { { title, collapsable: false, - children: ["", "kubernetes", "from-source"] + children: ["", "helm", "kubernetes", "from-source"] } ]; } diff --git a/docs/guide/helm.md b/docs/guide/helm.md new file mode 100644 index 000000000..09d774884 --- /dev/null +++ b/docs/guide/helm.md @@ -0,0 +1,72 @@ +# Helm + +This quickstart will show you how to deploy Pomerium with Helm. For the purpose of this guide, we will be using Google's Kubernetes Engine. However, there are many other ways to work with Kubernetes: + +- [Google Kubernetes Engine (GKE)](https://cloud.google.com/kubernetes-engine/) +- [Azure Kubernetes Service](https://azure.microsoft.com/en-us/services/kubernetes-service/) +- [Amazon Elastic Kubernetes Service (Amazon EKS)](https://aws.amazon.com/eks/) +- [OpenShift Kubernetes](https://www.openshift.com/learn/topics/kubernetes/) +- Or locally, with [minikube](https://kubernetes.io/docs/setup/minikube/) + +Most of the following steps should be very similar using any other provider, but may require additional tweaks. + + +## Prerequisites + +- A [Google Cloud Account](https://console.cloud.google.com/) +- A configured [identity provider] +- Install [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) +- Install the [Google Cloud SDK](https://cloud.google.com/kubernetes-engine/docs/quickstart) +- Install [helm](https://helm.sh/docs/using_helm/) + +## Download + +Retrieve the latest copy of pomerium's source-code by cloning the repository. + +```bash +git clone https://github.com/pomerium/pomerium.git $HOME/pomerium +``` + +## Configure + +Edit the the install command in the [helm_gke.sh script ][./scripts/helm_gke.sh] to match your [identity provider] settings. + + +Generate a wild-card TLS certificate. If you don't have one handy, the included [script] generates one from [LetsEncrypt]. + +## Run + +Run [./scripts/helm_gke.sh] which will: + +1. Provision a new cluster +2. Create authenticate, authorize, and proxy [deployments](https://cloud.google.com/kubernetes-engine/docs/concepts/deployment). +3. Provision and apply authenticate, authorize, and proxy [services](https://cloud.google.com/kubernetes-engine/docs/concepts/service). +4. Configure an ingress, Google's default load balancer. + +```bash +sh ./scripts/helm_gke.sh +``` + +You should see roughly the following in your terminal. Note, provisioning does take a few minutes. + +[![helm pomerium screencast](https://asciinema.org/a/223821.svg)]([https://asciinema.org/a/223821](https://asciinema.org/a/YcYC4iZLZi5kCCU5lQIWzFnhV) + +And if you check out Google's Kubernetes Engine dashboard you'll see something like: + +![Google's Kubernetes Engine dashboard](./kubernetes-gke.png) + +## Navigate + +Open a browser and navigate to `httpbin.corp.example.com`. + +You should see something like the following in your browser. + +![Getting started](./get-started.gif) + +[./scripts/helm_gke.sh]: ../docs/examples.html#google-kubernetes-engine +[example kubernetes files]: ../docs/examples.html#google-kubernetes-engine +[helloworld]: https://hub.docker.com/r/tutum/hello-world +[httpbin]: https://httpbin.org/ +[identity provider]: ../docs/identity-providers.md +[letsencrypt]: https://letsencrypt.org/ +[script]: https://github.com/pomerium/pomerium/blob/master/scripts/generate_wildcard_cert.sh diff --git a/docs/guide/kubernetes.md b/docs/guide/kubernetes.md index 6f29a99a1..544211715 100644 --- a/docs/guide/kubernetes.md +++ b/docs/guide/kubernetes.md @@ -10,11 +10,6 @@ This quickstart will show you how to deploy Pomerium with Kubernetes. For the pu Most of the following steps should be very similar using any other provider. -:::tip - -Google Cloud Platform has a [free trial with $300 credits](https://cloud.google.com/free/docs/gcp-free-tier). - -::: ## Prerequisites diff --git a/helm/Chart.yaml b/helm/Chart.yaml index d07d22f94..7206738c3 100644 --- a/helm/Chart.yaml +++ b/helm/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v1 name: pomerium -version: 0.0.3 +version: 1.0.0 appVersion: 0.0.3 home: http://www.pomerium.io/ icon: https://www.pomerium.io/logo.svg @@ -22,5 +22,5 @@ sources: engine: gotpl maintainers: -- name: bobby desimone +- name: desimone email: bobby.desimone@gmail.com diff --git a/helm/OWNERS b/helm/OWNERS new file mode 100644 index 000000000..5f53cd62f --- /dev/null +++ b/helm/OWNERS @@ -0,0 +1,5 @@ +approvers: +- desimone +reviewers: +- desimone +- victornoel \ No newline at end of file diff --git a/helm/README.md b/helm/README.md index 36ac7661b..049b336c3 100644 --- a/helm/README.md +++ b/helm/README.md @@ -1,9 +1,71 @@ # Pomerium -[Pomerium](https://github.com/pomerium/pomerium) is a tool for managing secure access to internal applications and resources. +[Pomerium](https://pomerium.io) is an [open-source](https://github.com/pomerium/pomerium) tool for managing secure access to internal applications and resources. ## TL;DR; ```console -$ helm install pomerium/pomerium +helm install --name my-release stable/pomerium ``` + +> Note: Pomerium depends on being configured with a third party identity providers to function properly. If you run pomerium without specifiying default values, you will need to change those configuration variables following setup. + +## Install the chart + +An example of a minimal, but complete installation of pomerium with identity provider settings, random secrets, certificates, and external URLs is as follows: + +```sh +helm install --name my-release \ + --set config.rootDomain="corp.example.com" \ + --set ingress.tls.certificate=$(base64 -i "*.corp.example.com.cer") \ + --set ingress.tls.key=$(base64 -i "*.corp.example.com.key") \ + --set config.policy=$(base64 -i "policy.yaml") \ + --set authenticate.idp.provider="google" \ + --set authenticate.idp.clientID="REPLACE_ME" \ + --set authenticate.idp.clientSecret="REPLACE_ME" + stable/pomerium +``` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +helm delete --purge my-release +``` + +The command removes nearly all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +A full listing of Pomerium's configuration variables can be found on the [config reference page](https://www.pomerium.io/docs/config-reference.html). + +Parameter | Description | Default +--------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- +`config.rootDomain` | Root Domain specifies the sub-domain handled by pomerium. [See more](https://www.pomerium.io/docs/config-reference.html#proxy-root-domains). | `corp.pomerium.io` +`config.generateTLS` | Generate a dummy Certificate Authority and certs for service communication. Manual CA and certs can be set in values. | `true` +`config.sharedSecret` | 256 bit key to secure service communication. [See more](https://www.pomerium.io/docs/config-reference.html#shared-secret). | 32 [random ascii chars](http://masterminds.github.io/sprig/strings.html) +`config.cookieSecret` | Cookie secret is a 32 byte key used to encrypt user sessions. | 32 [random ascii chars](http://masterminds.github.io/sprig/strings.html) +`config.policy` | Base64 encoded string containing the routes, and their access policies. | +`config.policyFile` | Relative file location of the policy file which contains the routes, and their access policies. | [See example](https://www.pomerium.io/docs/config-reference.html#policy) in values +`authenticate.name` | Name of the authenticate service. | `authenticate` +`authenticate.redirectUrl` | Redirect URL is the url the user will be redirected to following authentication with the third-party identity provider (IdP). [See more](https://www.pomerium.io/docs/config-reference.html#redirect-url). | `https://{{authenticate.name}}.{{config.rootDomain}}/oauth2/callback` +`authenticate.idp.provider` | Identity [Provider Name](https://www.pomerium.io/docs/config-reference.html#identity-provider-name). | `google` +`authenticate.idp.clientID` | Identity Provider oauth [client ID](https://www.pomerium.io/docs/config-reference.html#identity-provider-client-id). | Required +`authenticate.idp.clientSecret` | Identity Provider oauth [client secret](https://www.pomerium.io/docs/config-reference.html#identity-provider-client-secret). | Required +`authenticate.idp.url` | Identity [Provider URL](https://www.pomerium.io/docs/config-reference.html#identity-provider-url). | Optional +`authenticate.idp.serviceAccount` | Identity Provider [service account](https://www.pomerium.io/docs/config-reference.html#identity-provider-service-account). | Optional +`proxy.name` | Name of the proxy service. | `proxy` +`proxy.authenticateServiceUrl` | The externally accessible url for the authenticate service. | `https://{{authenticate.name}}.{{config.rootDomain}}` +`proxy.authorizeServiceUrl` | The externally accessible url for the authorize service. | `https://{{authorize.name}}.{{config.rootDomain}}` +`authorize.name` | Name of the authorize service. | `authorize` +`images.server.repository` | Pomerium image | `pomerium/pomerium` +`images.server.tag` | Pomerium image tag | `latest` +`images.server.pullPolicy` | Pomerium image pull policy | `Always` +`service.annotations` | Service annotations | `{}` +`service.externalPort` | Pomerium's port | `443` +`service.type` | Service type (ClusterIP, NodePort or LoadBalancer) | `ClusterIP` +`ingress.enabled` | Enables Ingress for pomerium | `false` +`ingress.annotations` | Ingress annotations | `{}` +`ingress.hosts` | Ingress accepted hostnames | `nil` +`ingress.tls` | Ingress TLS configuration | `[]` diff --git a/helm/templates/NOTES.txt b/helm/templates/NOTES.txt new file mode 100644 index 000000000..80ac288d7 --- /dev/null +++ b/helm/templates/NOTES.txt @@ -0,0 +1,67 @@ +{{- if eq (include "pomerium.providerOK" .) "true" }} +{{- if .Values.ingress.enabled }} +From outside the cluster, the server URL(s) are: +{{- range .Values.ingress.hosts }} + {{ $.Values.server.protocol }}://{{ . }} +{{- end }} + +{{- else if contains "NodePort" .Values.service.type }} + +Get the Pomerium URL by running: + export NODE_PORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "pomerium.fullname" . }}) + export NODE_IP=$(kubectl get nodes -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT/ + +{{- else if contains "LoadBalancer" .Values.service.type }} + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + Watch the status with: 'kubectl get svc -w {{ template "pomerium.fullname" . }}' + +Get the Pomerium URL by running: + export SERVICE_IP=$(kubectl get svc {{ template "pomerium.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo http://$SERVICE_IP/ +{{- else if contains "ClusterIP" .Values.service.type }} + +Get the Pomerium URL by running: + export POD_NAME=$(kubectl get pods -n {{ .Release.Namespace }} -l "component=server,app={{ template "pomerium.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo http://127.0.0.1:8000/ + kubectl -n {{ .Release.Namespace }} port-forward $POD_NAME 8000:8000 +{{- end }} +{{- else -}} +############################################################################## +#### ERROR: You did not set a valid identity provider #### +############################################################################## + +This deployment will be incomplete until you configure a valid version +control provider: + + helm upgrade {{ .Release.Name }} \ + --reuse-values \ + --set config.sharedSecret=$(head -c32 /dev/urandom | base64) \ + --set config.cookieSecret=$(head -c32 /dev/urandom | base64) \ + --set config.cert=$(base64 -i cert.pem) \ + --set config.key=$(base64 -i privkey.pem) \ + --set config.policy="$(cat policy.example.yaml | base64)" \ + --set authenticate.idp.provider="google" \ + --set config.rootDomain="corp.pomerium.io" \ + --set authenticate.redirectUrl="https://auth.corp.pomerium.io/oauth2/callback" \ + --set authenticate.idp.clientID="REPLACE_ME" \ + --set authenticate.idp.clientSecret="REPLACE_ME" \ + --set proxy.authenticateServiceUrl="https://auth.corp.pomerium.io" \ + --set proxy.authorizeServiceUrl="https://access.corp.pomerium.io" + stable/pomerium + +Currently supported providers: + + - Okta + - Google + - Azure Active Directory + - OneLogin + +See the values.yaml file to see what values are required for each provider. + +If you are having trouble with the configuration of a provider please visit +the official documentation: + + https://www.pomerium.io/docs/identity-providers.html +{{- end }} diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl index 527f08e9a..acf5a6051 100644 --- a/helm/templates/_helpers.tpl +++ b/helm/templates/_helpers.tpl @@ -35,3 +35,24 @@ If release name contains chart name it will be used as a full name. {{- end -}} {{- join "," $routes.routes | default "none=none" | quote -}} {{- end -}} + + +{{/* +Check if a valid source control provider has been set +Adapted from : https://github.com/helm/charts/blob/master/stable/drone/templates/_provider-envs.yaml +*/}} +{{- define "pomerium.providerOK" -}} +{{- if .Values.authenticate.idp -}} + {{- if eq .Values.authenticate.idp.clientID "" -}} + false + {{- else if eq .Values.authenticate.idp.clientSecret "" -}} + false + {{- else if eq .Values.authenticate.idp.clientID "REPLACE_ME" -}} + false + {{- else if eq .Values.authenticate.idp.clientSecret "REPLACE_ME" -}} + false + {{- else -}} + true + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/helm/templates/authenticate-deployment.yaml b/helm/templates/authenticate-deployment.yaml index b9aaeb4a9..df85ca2ad 100644 --- a/helm/templates/authenticate-deployment.yaml +++ b/helm/templates/authenticate-deployment.yaml @@ -1,13 +1,13 @@ -{{- if not .Values.omnibusMode -}} +{{- $secretName := default (include "pomerium.fullname" .) .Values.config.existingSecret }} apiVersion: apps/v1 kind: Deployment metadata: labels: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.authenticate.name }} chart: {{ template "pomerium.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} - name: {{ template "pomerium.fullname" . }}-authenticate + name: {{ template "pomerium.fullname" . }}-{{ .Values.authenticate.name }} {{- if .Values.annotations }} annotations: {{ toYaml .Values.annotations | indent 4 }} @@ -16,7 +16,7 @@ spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.authenticate.name }} release: {{ .Release.Name }} template: metadata: @@ -25,7 +25,7 @@ spec: {{ toYaml .Values.podAnnotations | indent 8 }} {{- end }} labels: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.authenticate.name }} chart: {{ template "pomerium.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} @@ -54,55 +54,51 @@ spec: - name: COOKIE_SECRET valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} + name: {{ $secretName }} key: cookie-secret - name: SHARED_SECRET valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} + name: {{ $secretName }} key: shared-secret - name: REDIRECT_URL - value: {{ .Values.authenticate.redirectUrl }} + value: {{ default (printf "https://%s.%s/oauth2/callback" .Values.authenticate.name .Values.config.rootDomain ) .Values.authenticate.redirectUrl }} - name: PROXY_ROOT_DOMAIN - value: {{ .Values.authenticate.proxyRootDomains }} + value: {{ .Values.config.rootDomain }} - name: IDP_PROVIDER value: {{ .Values.authenticate.idp.provider }} - name: IDP_CLIENT_ID valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} + name: {{ $secretName }} key: idp-client-id - name: IDP_CLIENT_SECRET valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} + name: {{ $secretName }} key: idp-client-secret -{{- if .Values.authenticate.idp.url }} - name: IDP_PROVIDER_URL value: {{ .Values.authenticate.idp.url }} -{{- end }} - -{{- if .Values.config.cert }} + - name: IDP_SERVICE_ACCOUNT + valueFrom: + secretKeyRef: + name: {{ $secretName }} + key: idp-service-account - name: CERTIFICATE valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} - key: certificate -{{- end }} -{{- if .Values.config.key }} + name: {{ $secretName }} + key: authenticate-cert - name: CERTIFICATE_KEY valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} - key: certificate-key -{{- end }} -{{- if .Values.config.ca }} + name: {{ $secretName }} + key: authenticate-key - name: CERTIFICATE_AUTHORITY valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} - key: certificate-authority -{{- end }} + name: {{ $secretName }} + key: ca-cert {{- range $name, $value := .Values.extraEnv }} - name: {{ $name }} value: {{ quote $value }} @@ -121,17 +117,6 @@ spec: path: /ping port: https scheme: HTTPS - - - volumeMounts: - - mountPath: /etc/pomerium/ - name: {{ template "pomerium.fullname" . }}-policy - - volumes: - - name: {{ template "pomerium.fullname" . }}-policy - configMap: - name: {{ template "pomerium.fullname" . }} - resources: {{ toYaml .Values.resources | indent 10 }} {{- if .Values.extraVolumes }} @@ -153,5 +138,4 @@ spec: {{- if .Values.affinity }} affinity: {{ toYaml .Values.affinity | indent 8 }} -{{- end }} -{{- end -}} \ No newline at end of file +{{- end }} \ No newline at end of file diff --git a/helm/templates/authenticate-service.yaml b/helm/templates/authenticate-service.yaml index acf63edb8..5670b55ab 100644 --- a/helm/templates/authenticate-service.yaml +++ b/helm/templates/authenticate-service.yaml @@ -1,10 +1,9 @@ -{{- if not .Values.omnibusMode -}} apiVersion: v1 kind: Service metadata: - name: {{ template "pomerium.fullname" . }}-authenticate + name: {{ template "pomerium.fullname" . }}-{{ .Values.authenticate.name }} labels: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.authenticate.name }} chart: {{ template "pomerium.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} @@ -21,11 +20,11 @@ spec: - port: {{ .Values.service.externalPort }} targetPort: https protocol: TCP - name: http + name: https + {{- if hasKey .Values.service "nodePort" }} nodePort: {{ .Values.service.nodePort }} {{- end }} selector: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.authenticate.name }} release: {{ .Release.Name }} -{{- end -}} diff --git a/helm/templates/authorize-deployment.yaml b/helm/templates/authorize-deployment.yaml index 728fa30b3..086394bfb 100644 --- a/helm/templates/authorize-deployment.yaml +++ b/helm/templates/authorize-deployment.yaml @@ -1,14 +1,14 @@ -{{- if not .Values.omnibusMode -}} - +{{- $configName := default (include "pomerium.fullname" .) .Values.config.existingConfig }} +{{- $secretName := default (include "pomerium.fullname" .) .Values.config.existingSecret }} apiVersion: apps/v1 kind: Deployment metadata: labels: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.authorize.name }} chart: {{ template "pomerium.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} - name: {{ template "pomerium.fullname" . }}-authorize + name: {{ template "pomerium.fullname" . }}-{{ .Values.authorize.name }} {{- if .Values.annotations }} annotations: {{ toYaml .Values.annotations | indent 4 }} @@ -17,7 +17,7 @@ spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.authorize.name }} release: {{ .Release.Name }} template: metadata: @@ -26,7 +26,7 @@ spec: {{ toYaml .Values.podAnnotations | indent 8 }} {{- end }} labels: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.authorize.name }} chart: {{ template "pomerium.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} @@ -55,9 +55,9 @@ spec: - name: SHARED_SECRET valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} + name: {{ $secretName }} key: shared-secret -{{- if .Values.config.policyFile }} +{{- if or .Values.config.existingConfig .Values.config.policyFile}} - name: POLICY_FILE value: /etc/pomerium/policy.yaml {{- end }} @@ -65,27 +65,21 @@ spec: - name: POLICY value: {{ .Values.config.policy }} {{- end }} -{{- if .Values.config.cert }} - name: CERTIFICATE valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} - key: certificate -{{- end }} -{{- if .Values.config.key }} + name: {{ $secretName }} + key: authorize-cert - name: CERTIFICATE_KEY valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} - key: certificate-key -{{- end }} -{{- if .Values.config.ca }} + name: {{ $secretName }} + key: authorize-key - name: CERTIFICATE_AUTHORITY valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} - key: certificate-authority -{{- end }} + name: {{ $secretName }} + key: ca-cert {{- range $name, $value := .Values.extraEnv }} - name: {{ $name }} value: {{ quote $value }} @@ -104,17 +98,15 @@ spec: path: /ping port: https scheme: HTTPS - - +{{- if or .Values.config.existingConfig .Values.config.policyFile}} volumeMounts: - mountPath: /etc/pomerium/ - name: {{ template "pomerium.fullname" . }}-policy - + name: policy volumes: - - name: {{ template "pomerium.fullname" . }}-policy + - name: policy configMap: - name: {{ template "pomerium.fullname" . }} - + name: {{ $configName }} +{{- end }} resources: {{ toYaml .Values.resources | indent 10 }} {{- if .Values.extraVolumes }} @@ -137,4 +129,3 @@ spec: affinity: {{ toYaml .Values.affinity | indent 8 }} {{- end }} -{{- end }} diff --git a/helm/templates/authorize-service.yaml b/helm/templates/authorize-service.yaml index e864ce6b2..c92075b96 100644 --- a/helm/templates/authorize-service.yaml +++ b/helm/templates/authorize-service.yaml @@ -1,10 +1,9 @@ -{{- if not .Values.omnibusMode -}} apiVersion: v1 kind: Service metadata: - name: {{ template "pomerium.fullname" . }}-authorize + name: {{ template "pomerium.fullname" . }}-{{ .Values.authorize.name }} labels: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.authorize.name }} chart: {{ template "pomerium.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} @@ -21,11 +20,11 @@ spec: - port: {{ .Values.service.externalPort }} targetPort: https protocol: TCP - name: http + name: https + {{- if hasKey .Values.service "nodePort" }} nodePort: {{ .Values.service.nodePort }} {{- end }} selector: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.authorize.name }} release: {{ .Release.Name }} -{{- end }} diff --git a/helm/templates/configmap.yaml b/helm/templates/configmap.yaml index c08478cb9..75e6dacd7 100644 --- a/helm/templates/configmap.yaml +++ b/helm/templates/configmap.yaml @@ -1,3 +1,4 @@ +{{- if not .Values.config.existingConfig }} apiVersion: v1 kind: ConfigMap metadata: @@ -9,3 +10,4 @@ metadata: release: {{ .Release.Name }} data: policy.yaml: {{toYaml .Values.config.policyFile | indent 4}} +{{- end }} diff --git a/helm/templates/ingress.yaml b/helm/templates/ingress.yaml index 83b48c9a8..4a5787002 100644 --- a/helm/templates/ingress.yaml +++ b/helm/templates/ingress.yaml @@ -1,40 +1,44 @@ {{- if .Values.ingress.enabled -}} -{{- $serviceName := include "pomerium.fullname" . -}} -{{- $servicePort := .Values.service.externalPort -}} -{{- $paths := .Values.ingress.paths -}} apiVersion: extensions/v1beta1 kind: Ingress metadata: - name: {{ template "pomerium.fullname" . }} + name: {{ include "pomerium.fullname" . }} labels: - app: {{ template "pomerium.name" . }} - chart: {{ template "pomerium.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} -{{- if .Values.ingress.labels }} {{ toYaml .Values.ingress.labels | indent 4 }} {{- end }} -{{- if .Values.ingress.annotations }} + app.kubernetes.io/name: {{ include "pomerium.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + helm.sh/chart: {{ include "pomerium.chart" . }} +{{- with .Values.ingress.annotations }} annotations: -{{ toYaml .Values.ingress.annotations | indent 4 }} +{{ toYaml . | indent 4 }} {{- end }} - spec: + tls: + - secretName: {{ default .Values.ingress.secretName .Values.ingress.secret.name}} + hosts: + - '*.{{ .Values.config.rootDomain }}' + - {{ .Values.authorize.name }}.{{ .Values.config.rootDomain }} + - {{ .Values.authenticate.name }}.{{ .Values.config.rootDomain }} rules: -{{- if .Values.ingress.extraRules }}{{ toYaml .Values.ingress.extraRules | indent 4 }}{{- end }} -{{- if .Values.ingress.hosts }} -{{- range $host := .Values.ingress.hosts }} - - host: {{ $host }} + - host: '*.{{ .Values.config.rootDomain }}' http: paths: -{{- range $p := $paths }} - - path: {{ $p }} + - paths: backend: - serviceName: {{ $serviceName }} - servicePort: {{ $servicePort }} -{{- end }} -{{- end }} -{{- end }} -{{- if .Values.ingress.tls }} - tls: -{{ toYaml .Values.ingress.tls | indent 4 }} -{{- end }} -{{- end }} + serviceName: {{ include "pomerium.fullname" .}}-{{ .Values.proxy.name }} + servicePort: https + - host: {{ .Values.authorize.name }}.{{ .Values.config.rootDomain }} + http: + paths: + - paths: + backend: + serviceName: {{ include "pomerium.fullname" .}}-{{ .Values.authorize.name }} + servicePort: https + - host: {{ .Values.authenticate.name }}.{{ .Values.config.rootDomain }} + http: + paths: + - paths: + backend: + serviceName: {{ include "pomerium.fullname" .}}-{{ .Values.authenticate.name }} + servicePort: https +{{- end }} \ No newline at end of file diff --git a/helm/templates/proxy-deployment.yaml b/helm/templates/proxy-deployment.yaml index 53fe48328..3b8f38a26 100644 --- a/helm/templates/proxy-deployment.yaml +++ b/helm/templates/proxy-deployment.yaml @@ -1,13 +1,14 @@ -{{- if not .Values.omnibusMode -}} +{{- $configName := default (include "pomerium.fullname" .) .Values.config.existingConfig }} +{{- $secretName := default (include "pomerium.fullname" .) .Values.config.existingSecret }} apiVersion: apps/v1 kind: Deployment metadata: labels: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.proxy.name }} chart: {{ template "pomerium.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} - name: {{ template "pomerium.fullname" . }}-proxy + name: {{ template "pomerium.fullname" . }}-{{ .Values.proxy.name }} {{- if .Values.annotations }} annotations: {{ toYaml .Values.annotations | indent 4 }} @@ -16,7 +17,7 @@ spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.proxy.name }} release: {{ .Release.Name }} template: metadata: @@ -25,7 +26,7 @@ spec: {{ toYaml .Values.podAnnotations | indent 8 }} {{- end }} labels: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.proxy.name }} chart: {{ template "pomerium.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} @@ -50,22 +51,26 @@ spec: {{- end }} env: - name: SERVICES - value: authorize + value: proxy - name: COOKIE_SECRET valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} + name: {{ $secretName }} key: cookie-secret - name: SHARED_SECRET valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} - key: shared-secret + name: {{ $secretName }} + key: shared-secret - name: AUTHENTICATE_SERVICE_URL - value: {{ .Values.proxy.authenticateServiceUrl }} + value: {{ default (printf "https://%s.%s" .Values.authenticate.name .Values.config.rootDomain ) .Values.proxy.authenticateServiceUrl }} - name: AUTHORIZE_SERVICE_URL - value: {{ .Values.proxy.authorizeServiceUrl }} -{{- if .Values.config.policyFile }} + value: {{ default (printf "https://%s.%s" .Values.authorize.name .Values.config.rootDomain ) .Values.proxy.authorizeServiceUrl }} + - name: AUTHENTICATE_INTERNAL_URL + value: {{ default (printf "%s-%s.%s.svc.cluster.local" (include "pomerium.fullname" .) .Values.authenticate.name .Release.Namespace ) .Values.proxy.authenticateInternalUrl}} + - name: AUTHORIZE_INTERNAL_URL + value: {{ default (printf "%s-%s.%s.svc.cluster.local" (include "pomerium.fullname" .) .Values.authorize.name .Release.Namespace ) .Values.proxy.authorizeInternalUrl}} +{{- if or .Values.config.existingConfig .Values.config.policyFile}} - name: POLICY_FILE value: /etc/pomerium/policy.yaml {{- end }} @@ -73,27 +78,21 @@ spec: - name: POLICY value: {{ .Values.config.policy }} {{- end }} -{{- if .Values.config.cert }} - name: CERTIFICATE valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} - key: certificate -{{- end }} -{{- if .Values.config.key }} + name: {{ $secretName }} + key: proxy-cert - name: CERTIFICATE_KEY valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} - key: certificate-key -{{- end }} -{{- if .Values.config.ca }} + name: {{ $secretName }} + key: proxy-key - name: CERTIFICATE_AUTHORITY valueFrom: secretKeyRef: - name: {{ template "pomerium.fullname" . }} - key: certificate-authority -{{- end }} + name: {{ $secretName }} + key: ca-cert {{- range $name, $value := .Values.extraEnv }} - name: {{ $name }} value: {{ quote $value }} @@ -112,17 +111,15 @@ spec: path: /ping port: https scheme: HTTPS - - +{{- if or .Values.config.existingConfig .Values.config.policyFile}} volumeMounts: - mountPath: /etc/pomerium/ - name: {{ template "pomerium.fullname" . }}-policy - + name: policy volumes: - - name: {{ template "pomerium.fullname" . }}-policy + - name: policy configMap: - name: {{ template "pomerium.fullname" . }} - + name: {{ $configName }} +{{- end }} resources: {{ toYaml .Values.resources | indent 10 }} {{- if .Values.extraVolumes }} @@ -144,5 +141,4 @@ spec: {{- if .Values.affinity }} affinity: {{ toYaml .Values.affinity | indent 8 }} -{{- end }} -{{- end }} +{{- end }} \ No newline at end of file diff --git a/helm/templates/proxy-service.yaml b/helm/templates/proxy-service.yaml index 4dce33263..5fbcaef30 100644 --- a/helm/templates/proxy-service.yaml +++ b/helm/templates/proxy-service.yaml @@ -1,10 +1,9 @@ -{{- if not .Values.omnibusMode }} apiVersion: v1 kind: Service metadata: - name: {{ template "pomerium.fullname" . }}-proxy + name: {{ template "pomerium.fullname" . }}-{{ .Values.proxy.name }} labels: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.proxy.name }} chart: {{ template "pomerium.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} @@ -21,11 +20,11 @@ spec: - port: {{ .Values.service.externalPort }} targetPort: https protocol: TCP - name: http + name: https + {{- if hasKey .Values.service "nodePort" }} nodePort: {{ .Values.service.nodePort }} {{- end }} selector: - app: {{ template "pomerium.name" . }} + app: {{ template "pomerium.name" . }}-{{ .Values.proxy.name }} release: {{ .Release.Name }} -{{- end }} \ No newline at end of file diff --git a/helm/templates/secret.yaml b/helm/templates/secret.yaml index 2fccc3d43..a6e276615 100644 --- a/helm/templates/secret.yaml +++ b/helm/templates/secret.yaml @@ -1,3 +1,4 @@ +{{- if not .Values.config.existingSecret }} apiVersion: v1 kind: Secret metadata: @@ -10,10 +11,34 @@ metadata: namespace: {{ .Release.Namespace }} type: Opaque data: - cookie-secret: {{ .Values.config.cookieSecret | b64enc | quote }} - shared-secret: {{ .Values.config.sharedSecret | b64enc | quote }} - idp-client-id: {{ .Values.authenticate.idp.clientID | b64enc | quote }} - idp-client-secret: {{ .Values.authenticate.idp.clientSecret | b64enc | quote }} - certificate: {{- if .Values.config.cert }} {{ .Values.config.cert | b64enc | quote }} {{- end }} - certificate-key: {{- if .Values.config.key }} {{ .Values.config.key | b64enc | quote }} {{- end }} - certificate-authority: {{- if .Values.config.ca }} {{ .Values.config.ca | b64enc | quote }} {{- end }} + cookie-secret: {{ default (randAscii 32 | b64enc | b64enc) (.Values.config.cookieSecret | b64enc )}} + shared-secret: {{ default (randAscii 32 | b64enc | b64enc) (.Values.config.sharedSecret | b64enc )}} + idp-client-id: {{ .Values.authenticate.idp.clientID | b64enc }} + idp-client-secret: {{ .Values.authenticate.idp.clientSecret | b64enc }} + idp-service-account: {{ .Values.authenticate.idp.serviceAccount | b64enc }} +{{- if .Values.config.generateTLS }} +{{- $ca := genCA "default-ca" 3650 }} +{{$authenticateSN:= list (printf "%s.%s" .Values.authenticate.name .Values.config.rootDomain) (printf "%s-%s.%s.svc.cluster.local" (include "pomerium.fullname" .) .Values.authenticate.name .Release.Namespace )}} +{{$authorizeSN:= list (printf "%s.%s" .Values.authorize.name .Values.config.rootDomain) (printf "%s-%s.%s.svc.cluster.local" (include "pomerium.fullname" .) .Values.authorize.name .Release.Namespace )}} +{{- $cn := default "example.com" .Values.config.rootDomain }} + ca-cert: {{ $ca.Cert | b64enc | b64enc }} + ca-key: {{ $ca.Key | b64enc | b64enc }} +{{- $kp := genSignedCert $cn ( default nil .Values.authenticate.tls.defaultIPList ) ( default $authenticateSN .Values.authenticate.tls.defaultSANList ) 3650 $ca }} + authenticate-cert: {{ $kp.Cert | b64enc | b64enc }} + authenticate-key: {{ $kp.Key | b64enc | b64enc }} +{{- $kp := genSignedCert $cn ( default nil .Values.authorize.tls.defaultIPList ) ( default $authorizeSN .Values.authorize.tls.defaultSANList ) 3650 $ca }} + authorize-cert: {{ $kp.Cert | b64enc | b64enc }} + authorize-key: {{ $kp.Key | b64enc | b64enc }} +{{- $kp := genSignedCert $cn ( default nil .Values.proxy.tls.defaultIPList ) ( default nil .Values.proxy.tls.defaultSANList ) 3650 $ca }} + proxy-cert: {{ $kp.Cert | b64enc | b64enc }} + proxy-key: {{ $kp.Key | b64enc | b64enc }} +{{- else -}} + ca-cert: {{ .Values.config.ca | b64enc }} + proxy-cert: {{ .Values.proxy.tls.cert | b64enc }} + proxy-key: {{ .Values.proxy.tls.key | b64enc }} + authenticate-cert: {{ .Values.authenticate.tls.cert | b64enc }} + authenticate-key: {{ .Values.authenticate.tls.key | b64enc }} + authorize-cert: {{ .Values.authorize.tls.cert | b64enc }} + authorize-key: {{ .Values.authorize.tls.key | b64enc }} +{{- end }} +{{- end }} diff --git a/helm/templates/tls-secrets.yaml b/helm/templates/tls-secrets.yaml index cd27011a5..4df9c8b1c 100644 --- a/helm/templates/tls-secrets.yaml +++ b/helm/templates/tls-secrets.yaml @@ -1,9 +1,9 @@ {{- if .Values.ingress.enabled }} -{{- range .Values.ingress.secrets }} +{{- if not .Values.ingress.secretName }} apiVersion: v1 kind: Secret metadata: - name: {{ .name }} + name: {{ default "pomerium-tls" .Values.ingress.secret.name }} labels: app: {{ template "pomerium.name" . }} chart: {{ template "pomerium.chart" . }} @@ -11,8 +11,8 @@ metadata: heritage: {{ .Release.Service | quote }} type: kubernetes.io/tls data: - tls.crt: {{ .certificate | b64enc }} - tls.key: {{ .key | b64enc }} + tls.crt: {{ .Values.ingress.secret.cert }} + tls.key: {{ .Values.ingress.secret.key }} --- {{- end }} {{- end }} diff --git a/helm/values.yaml b/helm/values.yaml index a8391ee96..d06bb9bb2 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -1,14 +1,15 @@ # For detailed explanation of each of the configuration settings see # https://www.pomerium.io/docs/config-reference.htmls -# run pomerium in "all-in-one" mode where all services are run from a single node -omnibusMode: false - -config: # settings that are shared by all services - sharedSecret: "LL3g/NoKkao7mTec2/wYSOZAki1VbR89q+kqbdFj0c4=" # head -c32 /dev/urandom | base64 - cookieSecret: "tAhd5A5Y8R/H/msFhkNdt8dCym2SatVbh4UrcDk3+Ms=" # head -c32 /dev/urandom | base64 - cert: # base64 -i cert.pem or using a volume - key: # base64 -i privkey.pem or using a volume +# settings that are shared by all services +config: + # routes under this wildcard domain are handled by pomerium + rootDomain: corp.pomerium.io + # existingSecret: + # existingConfig: + sharedSecret: "" + cookieSecret: "" + generateTLS: true policyFile: |- - from: httpbin.corp.pomerium.io to: http://httpbin @@ -30,69 +31,69 @@ config: # settings that are shared by all services allowed_groups: - admins +authenticate: + name: authenticate + redirectUrl: "" + # see https://www.pomerium.io/docs/identity-providers.html + idp: + provider: google + clientID: "REPLACE_ME" + clientSecret: "REPLACE_ME" + url: "" + serviceAccount: "" + tls: + cert: "" + key: "" + defaultSANList: [] + defaultIPList: [] -authenticate: # values specific to the authenticate service - name: authenticate # container name - redirectUrl: https://auth.corp.pomerium.io/oauth2/callback - proxyRootDomains: pomerium.io - idp: # see https://www.pomerium.io/docs/identity-providers.html - provider: okta - url: https://example.oktapreview.com/oauth2/default - clientID: "XXXXXXXX" - clientSecret: "XXXXXXXX" +authorize: + name: authorize + tls: + cert: "" + key: "" + defaultSANList: [] + defaultIPList: [] -authorize: # values specific to the authorize service - name: authorize # container name - -proxy: # values specific to the proxy service - name: proxy # container name - authenticateServiceUrl: https://auth.corp.pomerium.io - authorizeServiceUrl: https://access.corp.pomerium.io - -# For any other settings that are optional. for a complete listing see: -# https://www.pomerium.io/docs/config-reference.html -extraEnv: {} -extraArgs: {} -extraVolumes: {} - -image: - repository: "pomerium/pomerium" - tag: "latest" - pullPolicy: "IfNotPresent" +proxy: + name: proxy + tls: + cert: "" + key: "" + defaultSANList: [] + defaultIPList: [] + authenticateServiceUrl: "" + authorizeServiceUrl: "" + authorizeInternalUrl: "" + authenticateInternalUrl: "" service: + # Service type can be set to ClusterIP, NodePort or LoadBalancer. type: ClusterIP externalPort: 443 - annotations: {} - # foo.io/bar: "true" + annotations: + {} + # === GKE load balancer tweaks + # cloud.google.com/app-protocols: '{"https":"HTTPS"}' + # kubernetes.io/ingress.allow-http: "false" labels: {} ingress: - enabled: false - # path: / - # Used to create an Ingress record. - # hosts: - # - "*.corp.example.com" - # - "auth.corp.example.com" - # - "access.corp.example.com" - # annotations: - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - - # tls: - # Secrets must be manually created in the namespace. - # - secretName: pomerium-tls - # hosts: - # - chart-example.local - # secrets: - ## If you're providing your own certificates, please use this to add the certificates as secrets - ## key and certificate should start with -----BEGIN CERTIFICATE----- or - ## -----BEGIN RSA PRIVATE KEY----- - ## - # - name: pomerium-tls - # key: - # certificate: - + secretName: "" + secret: + name: "" + cert: "" + key: "" + enabled: true + annotations: + {} + # === nginx tweaks + # kubernetes.io/ingress.class: nginx + # nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + # nginx.ingress.kubernetes.io/proxy-buffer-size: "16k" + # === GKE load balancer tweaks == + # cloud.google.com/app-protocols: '{"https":"HTTPS"}' + # kubernetes.io/ingress.allow-http: "false" resources: {} # limits: @@ -119,3 +120,14 @@ priorityClassName: "" podAnnotations: {} podLabels: {} replicaCount: 1 + +# For any other settings that are optional. for a complete listing see: +# https://www.pomerium.io/docs/config-reference.html +extraEnv: {} +extraArgs: {} +extraVolumes: {} + +image: + repository: "pomerium/pomerium" + tag: "latest" + pullPolicy: "Always" diff --git a/scripts/helm_gke.sh b/scripts/helm_gke.sh index 7819847d2..4523958bc 100755 --- a/scripts/helm_gke.sh +++ b/scripts/helm_gke.sh @@ -1,7 +1,9 @@ #!/bin/bash -# PRE-REQ: -# 1) Install Helm : You should verify the content of this script before running. +# PRE-REQ: Install Helm : You should verify the content of this script before running. # curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash +# NOTE! This will create real resources on Google's cloud. Make sure you clean up any unused +# resources to avoid being billed. For reference, this tutorial cost me <10 cents for a couple of hours. +# NOTE! You must change the identity provider client secret setting, and service account setting! echo "=> [GCE] creating cluster" gcloud container clusters create pomerium @@ -26,22 +28,23 @@ echo "=> initialize Helm to install Tiller in your cluster" helm init --service-account=tiller helm repo update -echo "=> install pomerium with helm substituting configuration values as required; be sure to change these" -helm install helm/. \ - --set config.sharedSecret=$(head -c32 /dev/urandom | base64) \ - --set config.cookieSecret=$(head -c32 /dev/urandom | base64) \ - --set config.cert=$(base64 -i cert.pem) \ - --set config.key=$(base64 -i privkey.pem) \ - --set config.policy=$(cat policy.example.yaml) \ - --set authentiate.idp.provider="google" \ - --set authentiate.proxyRootDomains="pomerium.io" \ - --set authentiate.redirectUrl="https://auth.corp.pomerium.io/oauth2/callback" \ - --set authentiate.idp.clientID="REPLACE_ME" \ - --set authentiate.idp.clientSecret="REPLACE_ME" \ - --set proxy.authenticateServiceUrl="https://auth.corp.pomerium.io" \ - --set proxy.authorizeServiceUrl="https://access.corp.pomerium.io" +echo "=> wait a minute for tiller to get setup" +sleep 60 + +echo "=> install pomerium with helm" +echo " replace configuration settings to meet your specific needs and identity provider settings" + +helm install ./helm/ \ + --set service.type="NodePort" \ + --set config.rootDomain="corp.pomerium.io" \ + --set ingress.secret.name="pomerium-tls" \ + --set ingress.secret.cert=$(base64 -i "$HOME/.acme.sh/*.corp.pomerium.io_ecc/*.corp.pomerium.io.cer") \ + --set ingress.secret.key=$(base64 -i "$HOME/.acme.sh/*.corp.pomerium.io_ecc/*.corp.pomerium.io.key") \ + --set config.policy="$(cat policy.example.yaml | base64)" \ + --set authenticate.idp.provider="google" \ + --set authenticate.idp.clientID="REPLACE_ME.apps.googleusercontent.com" \ + --set authenticate.idp.clientSecret="REPLACE_ME" # When done, clean up by deleting the cluster! -# -# helm del $(helm ls --all --short) --purge #!!! DELETES ALL YOUR HELM INSTANCES! -# gcloud container clusters delete pomerium +# helm del $(helm ls --all --short) --purge # deletes all your helm instances +# gcloud container clusters delete pomerium # deletes your cluster