-
Notifications
You must be signed in to change notification settings - Fork 16.8k
Hydra #1022
Hydra #1022
Changes from 15 commits
9d999c4
a7615ba
561f81b
2c6c013
248efc6
0754457
a6ebc53
a45adf8
fc28d1e
b14c598
86e619f
a08870e
0c6e889
fd0bdbe
6cf8e1a
6f7e77c
e31ab4b
1b01a4f
9abd051
ab9dc74
1e90e1f
e01ead1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
apiVersion: v1 | ||
description: A security-first open source OAuth2 and OpenID Connect server for existing and new enterprise infrastructures. | ||
name: hydra | ||
version: 0.7.10 | ||
keywords: | ||
- hdyra | ||
- authentication | ||
- authorization | ||
- auth | ||
- oauth | ||
- jwt | ||
home: https://www.ory.am/products/hydra | ||
icon: https://github.com/ory/hydra/blob/master/docs/images/logo.png | ||
sources: | ||
- https://github.com/ory/hydra | ||
maintainers: | ||
- name: Kevin Minehart | ||
email: kminehart@wehco.com |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Hydra | ||
[Hydra](https://github/ory/hdya) offers OAuth 2.0 and OpenID Connect Core 1.0 capabilities as a service. Hydra is different, because it works with any existing authentication infrastructure, not just LDAP or SAML. By implementing a consent app (works with any programming language) you build a bridge between Hydra and your authentication infrastructure. | ||
|
||
Hydra is able to securely manage JSON Web Keys, and has a sophisticated policy-based access control you can use if you want to. | ||
|
||
This chart comes bundled with an installation of Postgres. | ||
|
||
# Prerequesites | ||
|
||
* Kubernetes 1.4+ with Beta APIs enabled | ||
* PV provisioner to support in the underlying infrastructure | ||
|
||
# Install | ||
|
||
To install the chart: | ||
|
||
``` | ||
helm install --name=my-release-name stable/hydra | ||
``` | ||
|
||
This will create a deployment, a secret, a service, and optionally a PersistentVolumeClaim, prefixed with `my-release-name`. | ||
|
||
# Uninstall | ||
|
||
``` | ||
helm delete my-release-name [--purge] | ||
``` | ||
|
||
Adding the `--purge` flag will completely remove any trace of your release. (No values will be remembered.) | ||
|
||
# Configuring | ||
|
||
|
||
| Parameter | Description | Default | | ||
|-------------------------------|----------------------------------------------------------------------------------------------------------------------------|--------------------------------| | ||
| `image` | The path for pulling the docker image (without tag) | `"oryd/hydra"` | | ||
| `imageTag` | The version of the docker image to pull | `"0.7.10"` | | ||
| `imagePullPolicy` | When to pull the docker image | `"Always"` | | ||
| `replicas` | How many replicas of Hydra to create | `2` | | ||
| `mountPath` | Where in the container to mount the storage volume | `"/root"` | | ||
| `persistence.enabled` | If false, then use `emptyDir: {}`, otherwise, issue a PVC | `true` | | ||
| `persistence.accessMode` | [ReadWriteOnce/ReadOnlyMany/ReadWriteMany](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes-1) | `ReadWriteOnce` | | ||
| `persistence.size` | How much storage to allocate to the volume | `1Gi` | | ||
| `postgresql.postgresPassword` | The password of the Postgres User managing Hydra | `hydra` | | ||
| `postgresql.persistence.size` | How much storage to allocate to the postgres server behind Hydra | `1Gi` | | ||
| `config.system.secret` | The secret password for encrypting authorization tokens. You should change this. | `"changeme_changeme_changeme"` | | ||
| `config.consentUrl` | The URL for the consent app | `"https://consent.example.com"`| | ||
| `config.logLevel` | How detailed should the log output be | `"debug"` | | ||
| `accessTokenLifespan` | How long should an access token be valid for | `"1h"` | | ||
| `idTokenLifespan` | How long should an id token be valid for | `"1h"` | | ||
| `authorizeCodeLifespan` | How long should an authorize code be valid for | `"1h"` | | ||
|
||
You can check out the [values.yaml](values.yaml) for any other configuration items not listed here. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
dependencies: | ||
- condition: "" | ||
enabled: false | ||
import-values: null | ||
name: postgresql | ||
repository: https://kubernetes-charts.storage.googleapis.com/ | ||
tags: null | ||
version: 0.6.0 | ||
digest: sha256:111f81da579687c7d392e5faf90dee60abcb036acbdbe5d2b31ff813a0aee54c | ||
generated: 2017-04-19T15:46:03.298854078-05:00 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
dependencies: | ||
- name: postgresql | ||
version: 0.6.0 | ||
repository: https://kubernetes-charts.storage.googleapis.com/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{{- if eq .Values.config.system.secret "this_is_a_secret_change_me" }} | ||
###################################################################### | ||
# WARNING # | ||
# You are using the default secret provided with the helm chart when # | ||
# issuing authorization tokens. This is very insecure. # | ||
###################################################################### | ||
{{- end }} | ||
|
||
Hydra should not be facing the internet itself, so you can access hydra via. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Part of Hydra's authorization flow requires a redirect to Hydra. It definitely does need to be publicly accessible. Overview of the OAuth2 Authorization Code flow This is incredibly simplified, but the key thing is that the user does need to be able to access Hydra from outside of the kubernetes cluster. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotya. Sorry about that! Part of the reason for me making this helm chart was so that I could set up Hydra on our cluster and give it a test run :P There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No worries. Let me know if I can help :) I too need to set up Hydra. Figured I'd go big or go home. |
||
the service from other deployments (including the consent app) using the hostname: | ||
|
||
{{ template "fullname" . }}-service.{{ $.Release.Namespace }}.svc.cluster.local | ||
|
||
Or on the same namespace: | ||
|
||
{{ template "fullname" . }}-service |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{{/* vim: set filetype=mustache: */}} | ||
{{/* | ||
Expand the name of the chart. | ||
*/}} | ||
{{- define "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). | ||
*/}} | ||
{{- define "fullname" -}} | ||
{{- $name := default .Chart.Name .Values.nameOverride -}} | ||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} | ||
{{- end -}} | ||
|
||
{{/* | ||
Create a default fully qualified postgresql name. | ||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). | ||
*/}} | ||
{{- define "postgresql.fullname" -}} | ||
{{- printf "%s-%s" .Release.Name "postgresql" | trunc 63 | trimSuffix "-" -}} | ||
{{- end -}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
apiVersion: extensions/v1beta1 | ||
kind: Deployment | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't it make more sense to use a Statefulset since you are using persistent storage? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @unguiculus Statefulset is still beta, not sure we should be pushing it yet There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if anything @kminehart I would consider removing postgres entirely from here, most people still aren't putting db's on k8s for a variety of reasons. Best method I have seen so far is the operator method, but still I think Hydra should just deploy agnostic of postgres, or use the postgres chart as a dependency There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @grillz Postgres chart as a dependency sounds good. It's probably best to have Hydra's chart set up its own database one way or the other because if left to their own devices, inexperienced system admins will likely configure Hydra to use the same database as the application, which is a major security hole. Maintaining database isolation is very important here, so it should be emphasized one way or another. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @20zinnm yeah I agree with that, but at the same time most of the k8s deployments were seeing right now are utilizing RDS or some hosted datastore, so I would hate to marry it either. Kind of a rock and a hard place There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If I understand correctly, the only thing you really need persistent storage for is the SSL certificates and CA files created by Hydra, right?
There's a solution to this problem in Helm already. By default, we will install the bundled postgres. In This way, users that will prefer using RDS can opt-in to using RDS, and those of us that don't care or prefer keeping everything in Kubernetes can keep it the way it is. It makes sense to me to make external database connections opt-in because it's always going to require configuration anyways. Keeping it bundled means the application will work out of the box without as much configuration. Bear with me, I'm still fairly new to Helm and Hydra. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I think that should work, Hydra should not be a statefulset, only postgres would be, but that should be a separate chart as mentioned. |
||
metadata: | ||
name: {{ template "fullname" . }} | ||
labels: | ||
app: {{ template "fullname" . }} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" | ||
release: "{{ .Release.Name }}" | ||
heritage: "{{ .Release.Service }}" | ||
spec: | ||
replicas: {{ .Values.replicas }} | ||
selector: | ||
matchLabels: | ||
app: {{ template "fullname" . }} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update selector for the label change: app: {{ template "name" . }}
release: "{{ .Release.Name }}" Apply everywhere. |
||
template: | ||
metadata: | ||
name: {{ template "fullname" . }} | ||
labels: | ||
app: {{ template "fullname" . }} | ||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" | ||
release: "{{ .Release.Name }}" | ||
heritage: "{{ .Release.Service }}" | ||
spec: | ||
volumes: | ||
- name: hydra-data | ||
{{- if .Values.persistence.enabled }} | ||
persistentVolumeClaim: | ||
claimName: {{ template "fullname" . }} | ||
{{- else }} | ||
emptyDir: {} | ||
{{- end }} | ||
- name: hydra-secret | ||
secret: | ||
secretName: {{ template "fullname" . }}-secret | ||
containers: | ||
- name: hydra | ||
image: {{ .Values.image }}:{{ .Values.imageTag }} | ||
imagePullPolicy: {{ .Values.imagePullPolicy }} | ||
command: ["hydra", "host"] | ||
volumeMounts: | ||
- name: hydra-data | ||
mountPath: {{ .Values.mountPath }} | ||
ports: | ||
- name: service | ||
containerPort: 4444 | ||
- name: service2 | ||
containerPort: 4445 | ||
env: | ||
- name: SYSTEM_SECRET | ||
valueFrom: | ||
secretKeyRef: | ||
name: {{ template "fullname" . }}-secret | ||
key: system.secret | ||
- name: DATABASE_URL | ||
value: postgres://{{ .Values.postgresql.postgresUser }}:{{ .Values.postgresql.postgresPassword }}@{{ template "postgresql.fullname" . }}:5432/{{ .Values.postgresql.postgresDatabase }}?sslmode=disable | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use secrets for passwords. Also, is there any other way to specify the password rather than in the URL? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @unguiculus I'm not sure using secrets for passwords should be a requirement, secrets in kubernetes are still not secure and wont be for some time There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @grillz if K8s is properly configured (TLS, don't let just anybody access the REST API) I don't see why a secret is any less secure than the deployment file. If an attacker gains access to the k8s API, the secret is compromised either way, no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @20zinnm For one this is a major compliance issue kubernetes/kubernetes#12742 . Not to mention the partitioning problem they are working are attempting to solve at the moment, but its not going to happen in the near future. Secrets just really aren't secret in k8s, and that no secret in the community. Sorry no pun intended 😉 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regardless, we should still put the password in a secret, especially now that RBAC is a thing, you can give someone access to deployments, and not secrets, and they won't be able to grab the database password. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can its just not actually secret, and RBAC is very limited in its ability to secure secrets at the moment. You can join sig-auth every other Wednesday where this is a hot topic. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we get around this by throwing these credentials into the environment from a secret? I.e. values.yaml --> secret --> environment? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That doesn't help much, our current setup is just using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's go ahead and set ourselves up for success :). I'll add a commit to kminehart/charts#1 with it as soon as I test it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess... kubernetes is a funny exercise in branding, call something a secret even if it isn't at all and people will use it as such ¯_(ツ)_/¯ |
||
- name: HTTPS_ALLOW_TERMINATION_FROM | ||
value: {{ .Values.config.httpsAllowTerminationFrom }} | ||
- name: LOG_LEVEL | ||
value: {{ .Values.config.logLevel }} | ||
- name: CONSENT_URL | ||
value: {{ .Values.config.consentUrl }} | ||
- name: ACCESS_TOKEN_LIFESPAN | ||
value: {{ .Values.config.accessTokenLifespan }} | ||
- name: ID_TOKEN_LIFESPAN | ||
value: {{ .Values.config.idTokenLifespan }} | ||
- name: AUTHORIZE_CODE_LIFESPAN | ||
value: {{ .Values.config.authorizeCodeLifespan }} | ||
resources: | ||
{{ toYaml .Values.resources | indent 12 }} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{{- if .Values.persistence.enabled }} | ||
kind: PersistentVolumeClaim | ||
apiVersion: v1 | ||
metadata: | ||
name: {{ template "fullname" . }} | ||
annotations: | ||
{{- if .Values.persistence.storageClass }} | ||
volume.beta.kubernetes.io/storage-class: {{ .Values.persistence.storageClass | quote }} | ||
{{- else }} | ||
volume.alpha.kubernetes.io/storage-class: default | ||
{{- end }} | ||
spec: | ||
accessModes: | ||
- {{ .Values.persistence.accessMode | quote }} | ||
resources: | ||
requests: | ||
storage: {{ .Values.persistence.size | quote }} | ||
{{- end }} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
apiVersion: v1 | ||
kind: Secret | ||
metadata: | ||
name: {{ template "fullname" . }}-secret | ||
labels: | ||
app: {{ template "fullname" . }} | ||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" | ||
release: "{{ .Release.Name }}" | ||
heritage: "{{ .Release.Service }}" | ||
type: Opaque | ||
data: | ||
system.secret: {{ .Values.config.system.secret | b64enc }} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
kind: Service | ||
apiVersion: v1 | ||
metadata: | ||
name: {{ template "fullname" . }}-service | ||
labels: | ||
app: {{ template "fullname" . }} | ||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" | ||
release: "{{ .Release.Name }}" | ||
heritage: "{{ .Release.Service }}" | ||
spec: | ||
type: {{ .Values.service.type }} | ||
selector: | ||
app: {{ template "fullname" . }} | ||
ports: | ||
- name: service | ||
port: {{ .Values.service.port }} | ||
targetPort: 4444 | ||
protocol: TCP |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
image: "oryd/hydra" | ||
imageTag: "v0.7.10" | ||
imagePullPolicy: "Always" | ||
|
||
replicas: 2 | ||
mountPath: "/root" | ||
|
||
# Persistent storage. | ||
persistence: | ||
## If this is false, then emptyDir: {} will be used. | ||
## Setting this to true is highly recommended for production use. | ||
## If this is false, you will lose your data when your pod is destroyed. | ||
enabled: true | ||
## If defined, volume.beta.kubernetes.io/storage-class: <storageClass> | ||
## Default: volume.alpha.kubernetes.io/storage-class: default | ||
# | ||
# storageClass: <storageClass> | ||
accessMode: ReadWriteOnce | ||
size: 1Gi | ||
|
||
postgresql: | ||
imageTag: "9.6" | ||
memory: 256Mi | ||
cpu: 250m | ||
postgresUser: hydra | ||
postgresPassword: hydra | ||
postgresDatabase: hydra | ||
persistence: | ||
size: 10Gi | ||
|
||
config: | ||
system: | ||
secret: "this_is_a_secret_change_me" | ||
consentUrl: "https://consent.example.com" | ||
logLevel: "debug" | ||
accessTokenLifespan: "1h" | ||
idTokenLifespan: "1h" | ||
authorizeCodeLifespan: "10m" | ||
httpsAllowTerminationFrom: 0.0.0.0/0 | ||
|
||
service: | ||
type: ClusterIP | ||
port: 4444 | ||
|
||
# http://kubernetes.io/docs/user-guide/compute-resources/ | ||
resources: | ||
requests: | ||
memory: 128Mi | ||
cpu: 100m |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason you still want to support 1.4?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No particular reason. 1.4 + Beta APIs is the minimum requirement, though. Honestly, I'd prefer to just remove this line anyways.