Skip to content

Commit

Permalink
Merge branch 'fix/update-path-to-csi' of https://github.com/stackable…
Browse files Browse the repository at this point in the history
…tech/secret-operator into fix/update-path-to-csi
  • Loading branch information
Maleware committed Jul 23, 2024
2 parents 2bd21aa + 683b6e3 commit b4bda57
Show file tree
Hide file tree
Showing 9 changed files with 332 additions and 0 deletions.
55 changes: 55 additions & 0 deletions deploy/helm/secret-operator/templates/secret_migration_job.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
# Migrates the TLS CA keypair from the hard-coded default namespace to the operator namespace
# See https://github.com/stackabletech/secret-operator/issues/453
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "operator.fullname" . }}-secret-migration
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-delete-policy": hook-succeeded
"helm.sh/hook-weight": "-5"
labels:
{{- include "operator.labels" . | nindent 4 }}
spec:
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "operator.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.image.pullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "operator.fullname" . }}-secret-migration-serviceaccount
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: migrate-secret
image: "{{ .Values.secretMigrationJob.image.repository }}:1.0.0-stackable{{ .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.secretMigrationJob.image.pullPolicy }}
resources:
{{ .Values.secretMigrationJob.resources | toYaml | nindent 12 }}
command: ["bash", "-c"]
args:
- |
#!/bin/bash
set -euo pipefail
SOURCE_NAMESPACE=default
TARGET_NAMESPACE={{ .Values.secretClasses.tls.caSecretNamespace | default .Release.Namespace }}
# only continue if secret exists
if source_ca_secret="$(kubectl get secret -n $SOURCE_NAMESPACE secret-provisioner-tls-ca -o json)"; then
echo "secret exists in namespace $SOURCE_NAMESPACE"
# only continue if secret in target namespace does NOT exist
if ! kubectl get secret -n $TARGET_NAMESPACE secret-provisioner-tls-ca; then
echo "secret does not exist in namespace $TARGET_NAMESPACE"
# copy secret from default to {{ .Values.secretClasses.tls.caSecretNamespace | default .Release.Namespace }}
echo "$source_ca_secret" | jq 'del(.metadata["namespace","creationTimestamp","resourceVersion","selfLink","uid"])' | kubectl apply -n $TARGET_NAMESPACE -f -
fi
fi
restartPolicy: Never
56 changes: 56 additions & 0 deletions deploy/helm/secret-operator/templates/secret_migration_rbac.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "operator.fullname" . }}-secret-migration-serviceaccount
labels:
{{- include "operator.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-delete-policy": hook-succeeded
"helm.sh/hook-weight": "-10"
{{- with .Values.serviceAccount.annotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "operator.fullname" . }}-secret-migration-clusterrolebinding
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-delete-policy": hook-succeeded
"helm.sh/hook-weight": "-10"
labels:
{{- include "operator.labels" . | nindent 4 }}
subjects:
- kind: ServiceAccount
name: {{ include "operator.fullname" . }}-secret-migration-serviceaccount
namespace: {{ .Release.Namespace }}
roleRef:
kind: ClusterRole
name: {{ include "operator.fullname" . }}-secret-migration-clusterrole
apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "operator.fullname" . }}-secret-migration-clusterrole
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-delete-policy": hook-succeeded
"helm.sh/hook-weight": "-10"
labels:
{{- include "operator.labels" . | nindent 4 }}
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- list
- watch
- create
- patch
- update
12 changes: 12 additions & 0 deletions deploy/helm/secret-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ image:
pullPolicy: IfNotPresent
pullSecrets: []

secretMigrationJob:
image:
repository: docker.stackable.tech/stackable/tools
pullPolicy: IfNotPresent
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 100m
memory: 128Mi

csiProvisioner:
image:
repository: docker.stackable.tech/k8s/sig-storage/csi-provisioner
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: my-app-tls # <1>
spec:
secretName: my-app-tls # <2>
secretTemplate:
labels:
secrets.stackable.tech/class: tls-cert-manager # <3>
secrets.stackable.tech/service: my-app # <4>
dnsNames:
- my-app # <5>
issuerRef:
kind: Issuer
name: secret-operator-demonstration # <6>
28 changes: 28 additions & 0 deletions docs/modules/secret-operator/examples/cert-manager/issuer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: secret-operator-demonstration # <1>
spec:
ca:
secretName: secret-operator-demonstration-ca
# Create a self-signed CA for secret-operator-demonstration to use
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: secret-operator-demonstration-ca
spec:
secretName: secret-operator-demonstration-ca
isCA: true
commonName: Stackable Secret Operator/Cert-Manager Demonstration CA
issuerRef:
kind: Issuer
name: secret-operator-demonstration-ca
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: secret-operator-demonstration-ca
spec:
selfSigned: {}
71 changes: 71 additions & 0 deletions docs/modules/secret-operator/examples/cert-manager/pod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: tls
mountPath: /tls
- name: config
mountPath: /etc/nginx/conf.d
ports:
- name: https
containerPort: 443
volumes:
- name: tls # <1>
ephemeral:
volumeClaimTemplate:
metadata:
annotations:
secrets.stackable.tech/class: tls-cert-manager # <2>
secrets.stackable.tech/scope: service=my-app # <3>
spec:
storageClassName: secrets.stackable.tech
accessModes:
- ReadWriteOnce
resources:
requests:
storage: "1"
- name: config
configMap:
name: my-app
--- # <4>
apiVersion: v1
kind: ConfigMap
metadata:
name: my-app
data:
default.conf: |
server {
listen 443 ssl;
ssl_certificate /tls/tls.crt;
ssl_certificate_key /tls/tls.key;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
--- # <5>
apiVersion: v1
kind: Service
metadata:
name: my-app
spec:
selector:
app: my-app
ports:
- name: https
port: 443
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
apiVersion: secrets.stackable.tech/v1alpha1
kind: SecretClass
metadata:
name: tls-cert-manager # <1>
spec:
backend:
k8sSearch:
searchNamespace:
pod: {} # <2>
82 changes: 82 additions & 0 deletions docs/modules/secret-operator/pages/cert-manager.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
= Cert-Manager Integration

https://cert-manager.io/[Cert-Manager] is a common tool to manage certificates in Kubernetes, especially when backed by an external
Certificate Authority (CA) such as https://letsencrypt.org/[Let\'s Encrypt].
The Stackable Secret Operator does not currently support managing Cert-Manager certificates directly, but it can be configured to consume certificates generated by it.
[#caveats]
== Caveats
Cert-Manager is designed to manage relatively long-lived certificates that are stored in Kubernetes Secrets. By contrast,
the Stackable Secret Operator is designed to generate temporary short-lived certificates.
This has a couple of repercussions:
- Longer-lived certificates mean that a leaked certificate has potential to be abused for longer.
- Application teams may have access to read Secrets in their respective applications' Namespaces.

Where possible, we recommend using the xref:secretclass.adoc#backend-autotls[`autoTls` backend] instead.

[#issuer]
== Configuring Cert-Manager

NOTE: We recommend using the xref:secretclass.adoc#backend-autotls[`autoTls` backend] instead for self-signed PKIs. We use Cert-Manager's CA issuer here to show the broader concepts.

To do this, you will first need to teach Cert-Manager how to create your certificates.

In a production setup this will likely use an external CA such as ACME or OpenBao/Vault. However, to make this guide self-contained, Cert-Manager will create
a self-signed CA certificate instead.

[source,yaml]
----
include::example$cert-manager/issuer.yaml[]
----
<1> This is the Issuer that our created certificates will reference later

[#secretclass]
== Creating a SecretClass

The Stackable Secret Operator needs to know how to find the certificates created by Cert-Manager. We do this by creating
a xref:secretclass.adoc[] using the xref:secretclass.adoc#backend-k8ssearch[`k8sSearch` backend], which can find arbitrary
Kubernetes Secret objects that have the correct labels.

[source,yaml]
----
include::example$cert-manager/secretclass.yaml[]
----
<1> Both certificates and Pods will reference this name, to ensure that the correct certificates are found
<2> This informs the Secret Operator that certificates will be found in the same namespace as the Pod using it

[#certificate]
== Requesting a certificate

You can now use Cert-Manager to provision your first certificate. Use labels to inform the Stackable Secret Operator
about which xref:scope.adoc[scopes] the certificate fulfills. Which scopes must be provisioned is going to depend
on the design of the workload. This guide assumes the xref:scope.adoc#service[service] scope.

[source,yaml]
----
include::example$cert-manager/certificate.yaml[]
----
<1> The Certificate name is irrelevant for the Stackable Secret Operator's, but must be unique (within the Namespace)
<2> The Secret name must also be unique within the Namespace
<3> This tells the Stackable Secret Operator that this secret corresponds to the SecretClass created xref:#secretclass[before]
<4> This secret fulfils the xref:scope.adoc#service[service] scope for `my-app`
<5> The list of DNS names that this certificate should apply to.
<6> The Cert-Manager Issuer that should sign this certificate, as created xref:#issuer[before]

[#pod]
== Using the certificate

Finally, we can create and expose a Pod that consumes the certificate!

[source,yaml]
----
include::example$cert-manager/pod.yaml[]
----
<1> A secret xref:volume.adoc[volume] is created, where the certificate will be exposed to the app
<2> The volume references the SecretClass defined xref:#secretclass[before]
<3> The app is designated the scope xref:scope#service[`service=my-app`], matching the xref:#certificate[certificate's scope]
<4> nginx is configured to use the mounted certificate
<5> nginx is exposed as a Kubernetes Service
2 changes: 2 additions & 0 deletions docs/modules/secret-operator/partials/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
** xref:secret-operator:secretclass.adoc[]
** xref:secret-operator:scope.adoc[]
** xref:secret-operator:volume.adoc[]
* Guides
** xref:secret-operator:cert-manager.adoc[]
* xref:secret-operator:security.adoc[]
* xref:secret-operator:reference/index.adoc[]
** xref:secret-operator:reference/crds.adoc[]
Expand Down

0 comments on commit b4bda57

Please sign in to comment.