diff --git a/charts/dex/.helmignore b/charts/dex/.helmignore new file mode 100644 index 0000000000..f0c1319444 --- /dev/null +++ b/charts/dex/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/charts/dex/Chart.yaml b/charts/dex/Chart.yaml new file mode 100644 index 0000000000..8c848bb14e --- /dev/null +++ b/charts/dex/Chart.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +appVersion: 2.19.0 +description: CoreOS Dex +home: https://github.com/dexidp/dex/ +icon: https://github.com/dexidp/dex/raw/master/Documentation/logos/dex-glyph-color.png +keywords: +- dex +- oidc +maintainers: +- email: Kevin.Fox@pnnl.gov + name: kfox1111 +- email: shane.starcher@gmail.com + name: sstarcher +- email: pete.brown@powerhrg.com + name: rendhalver +- email: vi7alya@gmail.com + name: vi7 +name: dex +version: 2.4.0 diff --git a/charts/dex/OWNERS b/charts/dex/OWNERS new file mode 100644 index 0000000000..3b79f6f4b8 --- /dev/null +++ b/charts/dex/OWNERS @@ -0,0 +1,6 @@ +approvers: +- desaintmartin +- vi7 +reviewers: +- desaintmartin +- vi7 diff --git a/charts/dex/README.md b/charts/dex/README.md new file mode 100644 index 0000000000..788bcffe9b --- /dev/null +++ b/charts/dex/README.md @@ -0,0 +1,102 @@ +# dex + +[Dex][dex] is an identity service that uses OpenID Connect to drive authentication for other apps. + +## Introduction + +Dex acts as a portal to other identity providers through "connectors." This lets dex defer authentication to LDAP servers, SAML providers, or established identity providers like GitHub, Google, and Active Directory. Clients write their authentication logic once to talk to dex, then dex handles the protocols for a given backend. + +**Kubernetes authentication note** + +If you plan to use dex as a [Kubernetes OpenID Connect token authenticator plugin](http://kubernetes.io/docs/admin/authentication/#openid-connect-tokens) you'll need to additionally deploy some helper app which will provide authentication UI for users and talk to dex. + +Several helper apps are listed below: + - https://github.com/mintel/dex-k8s-authenticator + - https://github.com/heptiolabs/gangway + - https://github.com/micahhausler/k8s-oidc-helper + - https://github.com/negz/kuberos + - https://github.com/negz/kubehook + - https://github.com/fydrah/loginapp + - https://github.com/keycloak/keycloak + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```sh +$ helm install --name my-release stable/dex +``` + +It'll install chart with the default parameters. However most probably it won't work for you as-is, thus before installing the chart you need to consult to the [values.yaml](values.yaml) notes as well as [dex documentation][dex]. + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```sh +$ helm delete --purge my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Upgrading an existing release to a new major version + +A major chart version change (like v1.5.1 -> v2.0.0) indicates that there is an incompatible breaking change which requires manual actions. + +### Upgrade to v2.0.0 + +Breaking changes which should be considered and require manual actions during release upgrade: + +- ability to switch grpc and https on and off via dedicated chart parameters +- port definition for Pod, Service and dex config re-written from scratch +- dex config is _not_ taken from `.Values.config` as-is anymore, pay attention! + +See the [Configuration](#configuration) section for the details on the parameters introduced in version 2.0.0. + +Moreover, this release updates all the labels to the new [recommended labels](https://github.com/helm/charts/blob/master/REVIEW_GUIDELINES.md#names-and-labels), most of them being immutable. + +In order to upgrade, please update your values file and uninstall/reinstall the chart. + +## Configuration + +Parameters introduced starting from v2 + +| Parameter | Description | Default | +| --------- | ----------- | ------- | +| `certs.grpc.pod.annotations` | Annotations for the pod created by the `grpc-certs` job | `{}` | +| `certs.web.pod.annotations` | Annotations for the pod created by the `web-certs` job | `{}` | +| `config.connectors` | Maps to the dex config `connectors` dict param | `{}` | +| `config.enablePasswordDB` | Maps to the dex config `enablePasswordDB` param | `true` | +| `config.frontend` | Maps to the dex config `frontend` dict param | `""` | +| `config.grpc.address` | dex grpc listen address | `127.0.0.1` | +| `config.grpc.tlsCert` | Maps to the dex config `grpc.tlsCert` param | `/etc/dex/tls/grpc/server/tls.crt` | +| `config.grpc.tlsClientCA` | Maps to the dex config `grpc.tlsClientCA` param | `/etc/dex/tls/grpc/ca/tls.crt` | +| `config.grpc.tlsKey` | Maps to the dex config `grpc.tlsKey` param | `/etc/dex/tls/grpc/server/tls.key` | +| `config.issuer` | Maps to the dex config `issuer` param | `http://dex.io:8080` | +| `config.logger` | Maps to the dex config `logger` dict param | `{"level": "debug"}` | +| `config.oauth2.alwaysShowLoginScreen` | Maps to the dex config `oauth2.alwaysShowLoginScreen` param | `false` | +| `config.oauth2.skipApprovalScreen` | Maps to the dex config `oauth2.skipApprovalScreen` param | `true` | +| `config.staticClients` | Maps to the dex config `staticClients` list param | `""` | +| `config.staticPasswords` | Maps to the dex config `staticPasswords` list param | `""` | +| `config.storage` | Maps to the dex config `storage` dict param | `{"type": "kubernetes", "config": {"inCluster": true}}` | +| `config.web.address` | dex http/https listen address | `0.0.0.0` | +| `config.web.tlsCert` | Maps to the dex config `web.tlsCert` param | `/etc/dex/tls/https/server/tls.crt` | +| `config.web.tlsKey` | Maps to the dex config `web.tlsKey` param | `/etc/dex/tls/https/server/tls.key` | +| `config.expiry.signingKeys` | Maps to the dex config `expiry.signingKeys` param | `6h` | +| `config.expiry.idTokens` | Maps to the dex config `expiry.idTokens` param | `24h` | +| `grpc` | Enable dex grpc endpoint | `true` | +| `https` | Enable TLS termination for the dex http endpoint | `false` | +| `ports.grpc.containerPort` | grpc port listened by the dex | `5000` | +| `ports.grpc.nodePort` | K8S Service node port for the dex grpc listener | `35000` | +| `ports.grpc.servicePort` | K8S Service port for the dex grpc listener | `35000` | +| `ports.web.containerPort` | http/https port listened by the dex | `5556` | +| `ports.web.nodePort` | K8S Service node port for the dex http/https listener | `32000` | +| `ports.web.servicePort` | K8S Service port for the dex http/https listener | `32000` | +| `service.loadBalancerIP` | IP override for K8S LoadBalancer Service | `""` | + + + +Check [values.yaml](values.yaml) notes together with [dex documentation][dex] and [config examples](https://github.com/dexidp/dex/tree/master/examples) for all the possible configuration options. + + +[dex]: https://github.com/dexidp/dex diff --git a/charts/dex/config/openssl.conf b/charts/dex/config/openssl.conf new file mode 100644 index 0000000000..e44be0eb5a --- /dev/null +++ b/charts/dex/config/openssl.conf @@ -0,0 +1,82 @@ +# OpenSSL configuration file. +# Adapted from https://github.com/coreos/matchbox/blob/master/examples/etc/matchbox/openssl.conf + +# default environment variable values +SAN = + +[ ca ] +# `man ca` +default_ca = CA_default + +[ CA_default ] +# Directory and file locations. +dir = . +certs = $dir/certs +crl_dir = $dir/crl +new_certs_dir = $dir/newcerts +database = $dir/index.txt +serial = $dir/serial +# certificate revocation lists. +crlnumber = $dir/crlnumber +crl = $dir/crl/intermediate-ca.crl +crl_extensions = crl_ext +default_crl_days = 30 +default_md = sha256 + +name_opt = ca_default +cert_opt = ca_default +default_days = 375 +preserve = no +policy = policy_loose + +[ policy_loose ] +# Allow the CA to sign a range of certificates. +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ req ] +# `man req` +default_bits = 4096 +distinguished_name = req_distinguished_name +string_mask = utf8only +default_md = sha256 + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +stateOrProvinceName = State or Province Name +localityName = Locality Name +0.organizationName = Organization Name +organizationalUnitName = Organizational Unit Name +commonName = Common Name + +# Certificate extensions (`man x509v3_config`) + +[ v3_ca ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +basicConstraints = critical, CA:true, pathlen:0 +keyUsage = critical, digitalSignature, cRLSign, keyCertSign + +[ usr_cert ] +basicConstraints = CA:FALSE +nsCertType = client +nsComment = "OpenSSL Generated Client Certificate" +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer +keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = clientAuth + +[ server_cert ] +basicConstraints = CA:FALSE +nsCertType = server +nsComment = "OpenSSL Generated Server Certificate" +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +keyUsage = critical, digitalSignature, keyEncipherment +extendedKeyUsage = serverAuth +subjectAltName = $ENV::SAN diff --git a/charts/dex/templates/NOTES.txt b/charts/dex/templates/NOTES.txt new file mode 100644 index 0000000000..b0010d49b1 --- /dev/null +++ b/charts/dex/templates/NOTES.txt @@ -0,0 +1,20 @@ +1. Get the application URL by running these commands: + +{{- if .Values.ingress.enabled }} +{{- range .Values.ingress.hosts }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "dex.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo https://$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. + You can watch the status of by running 'kubectl get svc -w {{ template "dex.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "dex.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo https://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "dex.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit https://127.0.0.1:8080/.well-known/openid-configuration to use your application" + kubectl port-forward $POD_NAME 8080:5556 +{{- end }} diff --git a/charts/dex/templates/_helpers.tpl b/charts/dex/templates/_helpers.tpl new file mode 100644 index 0000000000..e9f476d0b1 --- /dev/null +++ b/charts/dex/templates/_helpers.tpl @@ -0,0 +1,56 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "dex.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 "dex.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 "dex.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "dex.labels" -}} +app.kubernetes.io/name: {{ include "dex.name" . }} +helm.sh/chart: {{ include "dex.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "dex.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "dex.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/charts/dex/templates/clusterrole.yaml b/charts/dex/templates/clusterrole.yaml new file mode 100644 index 0000000000..2dea792e57 --- /dev/null +++ b/charts/dex/templates/clusterrole.yaml @@ -0,0 +1,15 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: +{{ include "dex.labels" . | indent 4 }} + name: {{ template "dex.fullname" . }} +rules: +- apiGroups: ["dex.coreos.com"] # API group created by dex + resources: ["*"] + verbs: ["*"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["create"] # To manage its own resources, dex must be able to create customresourcedefinitions +{{- end -}} diff --git a/charts/dex/templates/clusterrolebinding.yaml b/charts/dex/templates/clusterrolebinding.yaml new file mode 100644 index 0000000000..bc7370d9f5 --- /dev/null +++ b/charts/dex/templates/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: +{{ include "dex.labels" . | indent 4 }} + name: {{ template "dex.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "dex.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "dex.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/charts/dex/templates/config-openssl.yaml b/charts/dex/templates/config-openssl.yaml new file mode 100644 index 0000000000..fd3659d8fb --- /dev/null +++ b/charts/dex/templates/config-openssl.yaml @@ -0,0 +1,11 @@ +{{- if and .Values.grpc .Values.certs.grpc.create }} +apiVersion: v1 +kind: ConfigMap +metadata: + labels: +{{ include "dex.labels" . | indent 4 }} + name: {{ template "dex.fullname" . }}-openssl-config +data: + openssl.conf: | +{{ .Files.Get "config/openssl.conf" | indent 4 }} +{{- end }} diff --git a/charts/dex/templates/deployment.yaml b/charts/dex/templates/deployment.yaml new file mode 100644 index 0000000000..97d4035268 --- /dev/null +++ b/charts/dex/templates/deployment.yaml @@ -0,0 +1,114 @@ +{{ $fullname := include "dex.fullname" . }} +{{ $httpsTlsBuiltName := printf "%s-tls" $fullname }} +{{ $httpsTlsSecretName := default $httpsTlsBuiltName .Values.certs.web.secret.tlsName }} +{{ $grpcTlsServerBuiltName := printf "%s-server-tls" $fullname }} +{{ $grpcTlsServerSecretName := default $grpcTlsServerBuiltName .Values.certs.grpc.secret.serverTlsName }} +{{ $grpcCaBuiltName := printf "%s-ca" $fullname }} +{{ $grpcCaSecretName := default $grpcCaBuiltName .Values.certs.grpc.secret.caName }} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "dex.fullname" . }} + labels: +{{ include "dex.labels" . | indent 4 }} + app.kubernetes.io/component: dex +spec: + replicas: {{ .Values.replicas }} + strategy: + rollingUpdate: + maxSurge: 0 + maxUnavailable: 1 + type: RollingUpdate + selector: + matchLabels: + app.kubernetes.io/name: {{ include "dex.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: dex + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "dex.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: dex + annotations: + checksum/config: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: {{ template "dex.serviceAccountName" . }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 10 }} +{{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} +{{- end }} +{{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + containers: + - name: main + image: "{{ .Values.image }}:{{ .Values.imageTag }}" + imagePullPolicy: {{ .Values.imagePullPolicy }} + command: + - /usr/local/bin/dex + - serve + - /etc/dex/cfg/config.yaml + resources: +{{ toYaml .Values.resources | indent 10 }} + ports: + - name: {{ if .Values.https }}https{{ else }}http{{ end }} + containerPort: {{ .Values.ports.web.containerPort }} + protocol: TCP + {{- if .Values.grpc }} + - name: grpc + containerPort: {{ .Values.ports.grpc.containerPort }} + protocol: TCP + {{- end }} + env: +{{ toYaml .Values.env | indent 10 }} + volumeMounts: + - mountPath: /etc/dex/cfg + name: config +{{- if .Values.https }} + - mountPath: /etc/dex/tls/https/server + name: https-tls +{{- end }} +{{- if .Values.grpc }} + - mountPath: /etc/dex/tls/grpc/server + name: grpc-tls-server + - mountPath: /etc/dex/tls/grpc/ca + name: grpc-tls-ca +{{- end }} +{{- if ne (len .Values.extraVolumeMounts) 0 }} +{{ toYaml .Values.extraVolumeMounts | indent 8 }} +{{- end }} + volumes: + - secret: + defaultMode: 420 + items: + - key: config.yaml + path: config.yaml + secretName: {{ template "dex.fullname" . }} + name: config +{{- if .Values.https }} + - name: https-tls + secret: + defaultMode: 420 + secretName: {{ $httpsTlsSecretName | quote }} +{{- end }} +{{- if .Values.grpc }} + - name: grpc-tls-server + secret: + defaultMode: 420 + secretName: {{ $grpcTlsServerSecretName | quote }} + - name: grpc-tls-ca + secret: + defaultMode: 420 + secretName: {{ $grpcCaSecretName| quote }} +{{- end }} +{{- if ne (len .Values.extraVolumes) 0 }} +{{ toYaml .Values.extraVolumes | indent 6 }} +{{- end }} diff --git a/charts/dex/templates/ingress.yaml b/charts/dex/templates/ingress.yaml new file mode 100644 index 0000000000..22eef9568d --- /dev/null +++ b/charts/dex/templates/ingress.yaml @@ -0,0 +1,36 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "dex.fullname" . -}} +{{- $servicePort := .Values.ports.web.servicePort -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ $fullName }} + labels: +{{ include "dex.labels" . | indent 4 }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ . | quote }} + http: + paths: + - path: {{ $ingressPath }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $servicePort }} + {{- end }} +{{- end }} diff --git a/charts/dex/templates/job-grpc-certs.yaml b/charts/dex/templates/job-grpc-certs.yaml new file mode 100644 index 0000000000..dd75768bed --- /dev/null +++ b/charts/dex/templates/job-grpc-certs.yaml @@ -0,0 +1,108 @@ +{{- if and .Values.grpc .Values.certs.grpc.create }} +{{ $fullname := include "dex.fullname" . }} +{{ $tlsServerBuiltName := printf "%s-server-tls" $fullname }} +{{ $tlsServerSecretName := default $tlsServerBuiltName .Values.certs.grpc.secret.serverTlsName }} +{{ $tlsClientBuiltName := printf "%s-client-tls" $fullname }} +{{ $tlsClientSecretName := default $tlsClientBuiltName .Values.certs.grpc.secret.clientTlsName }} +{{ $caBuiltName := printf "%s-ca" $fullname }} +{{ $caName := default $caBuiltName .Values.certs.grpc.secret.caName }} +{{ $openSslConfigName := printf "%s-openssl-config" $fullname }} +{{ $local := dict "i" 0 }} +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + "helm.sh/hook": post-install + "helm.sh/hook-weight": "2" + "helm.sh/hook-delete-policy": hook-succeeded + name: {{ $fullname }}-grpc-certs + labels: +{{ include "dex.labels" . | indent 4 }} + app.kubernetes.io/component: "job-grpc-certs" +spec: + activeDeadlineSeconds: {{ .Values.certs.grpc.activeDeadlineSeconds }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "dex.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: "job-grpc-certs" +{{- if .Values.certs.grpc.pod.annotations }} + annotations: +{{ toYaml .Values.certs.grpc.pod.annotations | trim | indent 8 }} +{{- end }} + spec: + {{- if .Values.certs.securityContext.enabled }} + securityContext: + runAsUser: {{ .Values.certs.securityContext.runAsUser }} + fsGroup: {{ .Values.certs.securityContext.fsGroup }} + {{- end }} + serviceAccountName: {{ template "dex.serviceAccountName" . }} + restartPolicy: OnFailure + containers: + - name: main + image: "{{ .Values.certs.image }}:{{ .Values.certs.imageTag }}" + imagePullPolicy: {{ .Values.certs.imagePullPolicy }} + env: + - name: HOME + value: /tmp + workingDir: /tmp + command: + - /bin/bash + - -exc + - | + export CONFIG=/etc/dex/tls/grpc/openssl.conf; + cat << EOF > san.cnf + {{- $_ := set $local "i" 1 }} + {{- range .Values.certs.grpc.altNames }} + DNS.{{ $local.i }}:{{ . }} + {{- $_ := set $local "i" ( add1 $local.i ) }} + {{- end }} + {{- $_ := set $local "i" 1 }} + {{- range .Values.certs.grpc.altIPs }} + IP.{{ $local.i }}:{{ . }} + {{- $_ := set $local "i" ( add1 $local.i ) }} + {{- end }} + EOF + export SAN=$(cat san.cnf | paste -sd "," -) + + # Creating basic files/directories + mkdir -p {certs,crl,newcerts} + touch index.txt + touch index.txt.attr + echo 1000 > serial + # CA private key (unencrypted) + openssl genrsa -out ca.key 4096; + # Certificate Authority (self-signed certificate) + openssl req -config $CONFIG -new -x509 -days 3650 -sha256 -key ca.key -extensions v3_ca -out ca.crt -subj "/CN=grpc-ca"; + # Server private key (unencrypted) + openssl genrsa -out server.key 2048; + # Server certificate signing request (CSR) + openssl req -config $CONFIG -new -sha256 -key server.key -out server.csr -subj "/CN=grpc-server"; + # Certificate Authority signs CSR to grant a certificate + openssl ca -batch -config $CONFIG -extensions server_cert -days 365 -notext -md sha256 -in server.csr -out server.crt -cert ca.crt -keyfile ca.key; + # Client private key (unencrypted) + openssl genrsa -out client.key 2048; + # Signed client certificate signing request (CSR) + openssl req -config $CONFIG -new -sha256 -key client.key -out client.csr -subj "/CN=grpc-client"; + # Certificate Authority signs CSR to grant a certificate + openssl ca -batch -config $CONFIG -extensions usr_cert -days 365 -notext -md sha256 -in client.csr -out client.crt -cert ca.crt -keyfile ca.key; + # Remove CSR's + rm *.csr; + + # Cleanup the existing configmap and secrets + kubectl delete configmap {{ $caName }} --namespace {{ .Release.Namespace }} || true + kubectl delete secret {{ $caName }} {{ $tlsServerSecretName }} {{ $tlsClientSecretName }} --namespace {{ .Release.Namespace }} || true + kubectl create configmap {{ $caName }} --namespace {{ .Release.Namespace }} --from-file=ca.crt; + # Store all certficates in secrets + kubectl create secret tls {{ $caName }} --namespace {{ .Release.Namespace }} --cert=ca.crt --key=ca.key; + kubectl create secret tls {{ $tlsServerSecretName }} --namespace {{ .Release.Namespace }} --cert=server.crt --key=server.key; + kubectl create secret tls {{ $tlsClientSecretName }} --namespace {{ .Release.Namespace }} --cert=client.crt --key=client.key; + volumeMounts: + - name: openssl-config + mountPath: /etc/dex/tls/grpc + volumes: + - name: openssl-config + configMap: + name: {{ $openSslConfigName }} +{{- end }} diff --git a/charts/dex/templates/job-web-certs.yaml b/charts/dex/templates/job-web-certs.yaml new file mode 100644 index 0000000000..bf02e15038 --- /dev/null +++ b/charts/dex/templates/job-web-certs.yaml @@ -0,0 +1,99 @@ +{{- if .Values.certs.web.create }} +{{ $fullname := include "dex.fullname" . }} +{{ $tlsBuiltName := printf "%s-tls" $fullname }} +{{ $tlsSecretName := default $tlsBuiltName .Values.certs.web.secret.tlsName }} +{{ $caBuiltName := printf "%s-ca" $fullname }} +{{ $caName := default $caBuiltName .Values.certs.web.secret.caName }} +{{ $local := dict "i" 0 }} +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + "helm.sh/hook": post-install + "helm.sh/hook-weight": "1" + "helm.sh/hook-delete-policy": hook-succeeded + name: {{ $fullname }}-web-certs + labels: +{{ include "dex.labels" . | indent 4 }} + app.kubernetes.io/component: "job-web-certs" +spec: + activeDeadlineSeconds: {{ .Values.certs.web.activeDeadlineSeconds }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "dex.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: "job" +{{- if .Values.certs.web.pod.annotations }} + annotations: +{{ toYaml .Values.certs.web.pod.annotations | trim | indent 8 }} +{{- end }} + spec: + {{- if .Values.certs.securityContext.enabled }} + securityContext: + runAsUser: {{ .Values.certs.securityContext.runAsUser }} + fsGroup: {{ .Values.certs.securityContext.fsGroup }} + {{- end }} + serviceAccountName: {{ template "dex.serviceAccountName" . }} + restartPolicy: OnFailure + containers: + - name: main + image: "{{ .Values.certs.image }}:{{ .Values.certs.imageTag }}" + imagePullPolicy: {{ .Values.certs.imagePullPolicy }} + env: + - name: HOME + value: /tmp + workingDir: /tmp + command: + - /bin/bash + - -exc + - | + cat << EOF > req.cnf + [req] + req_extensions = v3_req + distinguished_name = req_distinguished_name + + [req_distinguished_name] + + [ v3_req ] + basicConstraints = CA:FALSE + keyUsage = nonRepudiation, digitalSignature, keyEncipherment + subjectAltName = @alt_names + + [alt_names] + {{- $_ := set $local "i" 1 }} + {{- range .Values.certs.web.altNames }} + DNS.{{ $local.i }} = {{ . }} + {{- $_ := set $local "i" ( add1 $local.i ) }} + {{- end }} + {{- $_ := set $local "i" 1 }} + {{- range .Values.certs.web.altIPs }} + IP.{{ $local.i }} = {{ . }} + {{- $_ := set $local "i" ( add1 $local.i ) }} + {{- end }} + EOF + + openssl genrsa -out ca-key.pem 2048; + openssl req -x509 -new -nodes -key ca-key.pem -days {{ .Values.certs.web.caDays }} -out ca.pem -subj "/CN=dex-ca"; + + openssl genrsa -out key.pem 2048; + openssl req -new -key key.pem -out csr.pem -subj "/CN=dex" -config req.cnf; + openssl x509 -req -in csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -days {{ .Values.certs.web.certDays }} -extensions v3_req -extfile req.cnf; + + kubectl delete configmap {{ $caName | quote }} --namespace {{ .Release.Namespace }} || true + kubectl delete secret {{ $caName | quote }} {{ $tlsSecretName }} --namespace {{ .Release.Namespace }} || true + + kubectl create configmap {{ $caName | quote }} --namespace {{ .Release.Namespace }} --from-file dex-ca.pem=ca.pem; + kubectl create secret tls {{ $caName | quote }} --namespace {{ .Release.Namespace }} --cert=ca.pem --key=ca-key.pem; + kubectl create secret tls {{ $tlsSecretName }} --namespace {{ .Release.Namespace }} --cert=cert.pem --key=key.pem; +{{- if .Values.inMiniKube }} + cp -a ca.pem /var/lib/localkube/oidc.pem + volumeMounts: + - mountPath: /var/lib/localkube + name: localkube + volumes: + - name: localkube + hostPath: + path: /var/lib/localkube +{{- end }} +{{- end }} diff --git a/charts/dex/templates/poddisruptionbudget.yaml b/charts/dex/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000000..0757558265 --- /dev/null +++ b/charts/dex/templates/poddisruptionbudget.yaml @@ -0,0 +1,14 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ template "dex.fullname" . }} + labels: +{{ include "dex.labels" . | indent 4 }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: {{ include "dex.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end -}} diff --git a/charts/dex/templates/role.yaml b/charts/dex/templates/role.yaml new file mode 100644 index 0000000000..055a1a272a --- /dev/null +++ b/charts/dex/templates/role.yaml @@ -0,0 +1,15 @@ +{{- if .Values.rbac.create }} +{{- if or .Values.certs.grpc.create .Values.certs.web.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: +{{ include "dex.labels" . | indent 4 }} + name: {{ template "dex.fullname" . }} + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: [""] + resources: ["configmaps", "secrets"] + verbs: ["create", "delete"] +{{- end -}} +{{- end -}} diff --git a/charts/dex/templates/rolebinding.yaml b/charts/dex/templates/rolebinding.yaml new file mode 100644 index 0000000000..89e9334aae --- /dev/null +++ b/charts/dex/templates/rolebinding.yaml @@ -0,0 +1,19 @@ +{{- if .Values.rbac.create }} +{{- if or .Values.certs.grpc.create .Values.certs.web.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: +{{ include "dex.labels" . | indent 4 }} + name: {{ template "dex.fullname" . }} + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "dex.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "dex.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end -}} +{{- end -}} diff --git a/charts/dex/templates/secret.yaml b/charts/dex/templates/secret.yaml new file mode 100644 index 0000000000..244fd05fc3 --- /dev/null +++ b/charts/dex/templates/secret.yaml @@ -0,0 +1,51 @@ +apiVersion: v1 +kind: Secret +metadata: + labels: +{{ include "dex.labels" . | indent 4 }} + name: {{ template "dex.fullname" . }} +stringData: + config.yaml: |- + {{- with .Values.config }} + issuer: {{ .issuer }} + storage: +{{ toYaml .storage | indent 6 }} + logger: +{{ toYaml .logger | indent 6 }} + web: + {{- if $.Values.https }} + https: {{ $.Values.config.web.address }}:{{ $.Values.ports.web.containerPort }} + tlsCert: {{ .web.tlsCert }} + tlsKey: {{ .web.tlsKey }} + {{- else }} + http: {{ $.Values.config.web.address }}:{{ $.Values.ports.web.containerPort }} + {{- end }} + {{- if $.Values.grpc }} + grpc: + addr: {{ $.Values.config.grpc.address }}:{{ $.Values.ports.grpc.containerPort }} + tlsCert: {{ .grpc.tlsCert }} + tlsKey: {{ .grpc.tlsKey }} + tlsClientCA: {{ .grpc.tlsClientCA }} + {{- end }} + {{- if .connectors }} + connectors: +{{ toYaml .connectors | indent 4 }} + {{- end }} + oauth2: {{ toYaml .oauth2 | nindent 6 }} + {{- if .staticClients }} + staticClients: +{{ toYaml .staticClients | indent 4 }} + {{- end }} + enablePasswordDB: {{ .enablePasswordDB }} + {{- if .staticPasswords }} + staticPasswords: +{{ toYaml .staticPasswords | indent 4 }} + {{- end }} + {{- if .expiry }} + expiry: +{{ toYaml .expiry | indent 6 }} + {{- end }} + {{- if .frontend }} + frontend: {{ toYaml .frontend | nindent 6 }} + {{- end }} + {{- end }} diff --git a/charts/dex/templates/service.yaml b/charts/dex/templates/service.yaml new file mode 100644 index 0000000000..d69ec1147e --- /dev/null +++ b/charts/dex/templates/service.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "dex.fullname" . }} + labels: +{{ include "dex.labels" . | indent 4 }} +{{- if .Values.service.annotations }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +{{- end }} +spec: + type: {{ .Values.service.type}} + sessionAffinity: None + ports: + - name: {{ if .Values.https }}https{{ else }}http{{ end }} + targetPort: {{ if .Values.https }}https{{ else }}http{{ end }} +{{- if eq "NodePort" .Values.service.type }} + nodePort: {{ .Values.ports.web.nodePort }} +{{- end }} + port: {{ .Values.ports.web.servicePort }} +{{- if .Values.grpc }} + - name: grpc + targetPort: grpc + {{- if eq "NodePort" .Values.service.type }} + nodePort: {{ .Values.ports.grpc.nodePort }} + {{- end }} + port: {{ .Values.ports.grpc.servicePort }} +{{- end }} +{{- if hasKey .Values.service "externalIPs" }} + externalIPs: +{{ toYaml .Values.service.externalIPs | indent 4 }} +{{- end }} +{{- if hasKey .Values.service "loadBalancerIP" }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} +{{- end }} + selector: + app.kubernetes.io/name: {{ include "dex.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/charts/dex/templates/serviceaccount.yaml b/charts/dex/templates/serviceaccount.yaml new file mode 100644 index 0000000000..8d39c4384f --- /dev/null +++ b/charts/dex/templates/serviceaccount.yaml @@ -0,0 +1,8 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: +{{ include "dex.labels" . | indent 4 }} + name: {{ template "dex.serviceAccountName" . }} +{{- end -}} diff --git a/charts/dex/values.yaml b/charts/dex/values.yaml new file mode 100644 index 0000000000..82406ff017 --- /dev/null +++ b/charts/dex/values.yaml @@ -0,0 +1,192 @@ +# Default values for dex +# This is a YAML-formatted file. +# Declare name/value pairs to be passed into your templates. +# name: value + +image: quay.io/dexidp/dex +imageTag: "v2.19.0" +imagePullPolicy: "IfNotPresent" + +inMiniKube: false + +nodeSelector: {} + +podAnnotations: {} + +tolerations: [] + # - key: CriticalAddonsOnly + # operator: Exists + # - key: foo + # operator: Equal + # value: bar + # effect: NoSchedule + +replicas: 1 + +# resources: + # limits: + # cpu: 100m + # memory: 50Mi + # requests: + # cpu: 100m + # memory: 50Mi + +# grpc support +grpc: true + +# https termination by dex itself +https: false + +ports: + web: + containerPort: 5556 + # for service.type: NodePort + nodePort: 32000 + servicePort: 32000 +# Relevant only when grpc support is enabled + grpc: + containerPort: 5000 + # for service.type: NodePort + nodePort: 35000 + servicePort: 35000 + +service: + type: ClusterIP + # Override IP for the Service Type: LoadBalancer. + # This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. + # loadBalancerIP: 127.0.0.1 + annotations: {} + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + path: / + hosts: + - dex.example.com + tls: [] + # - secretName: dex-example-tls + # hosts: + # - dex.example.com + +extraVolumes: [] +extraVolumeMounts: [] + +certs: + securityContext: + enabled: true + runAsUser: 65534 + fsGroup: 65534 + image: gcr.io/google_containers/kubernetes-dashboard-init-amd64 + imageTag: "v1.0.0" + imagePullPolicy: "IfNotPresent" + # Section below is relevant only when https termination is enabled + web: + create: true + activeDeadlineSeconds: 300 + caDays: 10000 + certDays: 10000 + altNames: + - dex.io + altIPs: {} + secret: + tlsName: dex-web-server-tls + caName: dex-web-server-ca + pod: + annotations: {} + # Section below is relevant only when grpc support is enabled + grpc: + create: true + activeDeadlineSeconds: 300 + altNames: + - dex.io + altIPs: {} + secret: + serverTlsName: dex-grpc-server-tls + clientTlsName: dex-grpc-client-tls + caName: dex-grpc-ca + pod: + annotations: {} + +env: [] + +rbac: + # Specifies whether RBAC resources should be created + create: true + +serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + name: + +affinity: {} + # podAntiAffinity: + # preferredDuringSchedulingIgnoredDuringExecution: + # - weight: 5 + # podAffinityTerm: + # topologyKey: "kubernetes.io/hostname" + # labelSelector: + # matchLabels: + # app: {{ template "dex.name" . }} + # release: "{{ .Release.Name }}" + +podDisruptionBudget: {} + # maxUnavailable: 1 + +config: + issuer: http://dex.io:8080 + storage: + type: kubernetes + config: + inCluster: true + logger: + level: debug + web: + # port is taken from ports section above + address: 0.0.0.0 + tlsCert: /etc/dex/tls/https/server/tls.crt + tlsKey: /etc/dex/tls/https/server/tls.key +# Section below is relevant only when grpc support is enabled + grpc: + # port is taken from ports section above + address: 127.0.0.1 + tlsCert: /etc/dex/tls/grpc/server/tls.crt + tlsKey: /etc/dex/tls/grpc/server/tls.key + tlsClientCA: /etc/dex/tls/grpc/ca/tls.crt + connectors: {} +# - type: github +# id: github +# name: GitHub +# config: +# clientID: xxxxxxxxxxxxxxx +# clientSecret: yyyyyyyyyyyyyyyyyyyyy +# redirectURI: https://dex.minikube.local:5556/callback +# org: kubernetes + oauth2: + alwaysShowLoginScreen: false + skipApprovalScreen: true + +# expiry: +# signingKeys: "6h" +# idTokens: "24h" + +# staticClients: +# - id: example-app +# redirectURIs: +# - 'http://192.168.42.219:31850/oauth2/callback' +# name: 'Example App' +# secret: ZXhhbXBsZS1hcHAtc2VjcmV0 +# + enablePasswordDB: true +# staticPasswords: +# - email: "admin@example.com" +# # bcrypt hash of the string "password" +# hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" +# username: "admin" +# userID: "08a8684b-db88-4b73-90a9-3cd1661f5466" + +# frontend: +# logoURL: https://example.com/yourlogo.png