mirror of
https://github.com/marcel-dempers/docker-development-youtube-series.git
synced 2025-06-06 17:01:30 +00:00
sealedsecrets prototype
This commit is contained in:
parent
ec8bfc9325
commit
655764b074
231
kubernetes/secrets/sealed-secrets/README.md
Normal file
231
kubernetes/secrets/sealed-secrets/README.md
Normal file
@ -0,0 +1,231 @@
|
||||
# Introduction to Sealed Secrets
|
||||
|
||||
Checkout the [Sealed Secrets GitHub Repo](https://github.com/bitnami-labs/sealed-secrets) </br>
|
||||
|
||||
## Create a kubernetes cluster
|
||||
|
||||
In this guide we we''ll need a Kubernetes cluster for testing. Let's create one using [kind](https://kind.sigs.k8s.io/) </br>
|
||||
|
||||
```
|
||||
kind create cluster --name sealedsecrets --image kindest/node:v1.23.5
|
||||
```
|
||||
|
||||
See cluster up and running:
|
||||
|
||||
```
|
||||
kubectl get nodes
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
sealedsecrets-control-plane Ready control-plane,master 2m12s v1.23.5
|
||||
```
|
||||
|
||||
## Run a container to work in
|
||||
|
||||
### run Alpine Linux:
|
||||
```
|
||||
docker run -it --rm -v ${HOME}:/root/ -v ${PWD}:/work -w /work --net host alpine sh
|
||||
```
|
||||
|
||||
### install kubectl
|
||||
|
||||
```
|
||||
apk add --no-cache curl
|
||||
curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
|
||||
chmod +x ./kubectl
|
||||
mv ./kubectl /usr/local/bin/kubectl
|
||||
```
|
||||
|
||||
### test cluster access:
|
||||
```
|
||||
/work # kubectl get nodes
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
sealedsecrets-control-plane Ready control-plane,master 3m26s v1.23.5
|
||||
```
|
||||
|
||||
## Install Sealed Secret Controller
|
||||
|
||||
### download the YAML
|
||||
|
||||
In this demo we'll use version [0.19.1](https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.19.1/controller.yaml) of the sealed secrets controller downloaded from the
|
||||
[Github releases](https://github.com/bitnami-labs/sealed-secrets/releases) page
|
||||
|
||||
```
|
||||
curl -L -o ./kubernetes/secrets/sealed-secrets/controller-v0.19.1.yaml https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.19.1/controller.yaml
|
||||
|
||||
```
|
||||
|
||||
### alternative install Helm
|
||||
|
||||
TODO: cover helm https://github.com/bitnami-labs/sealed-secrets#helm-chart
|
||||
|
||||
### install the controller
|
||||
|
||||
```
|
||||
kubectl apply -f kubernetes/secrets/sealed-secrets/controller-v0.19.1.yaml
|
||||
```
|
||||
|
||||
### Check the install
|
||||
|
||||
```
|
||||
kubectl -n kube-system get pods
|
||||
```
|
||||
|
||||
TODO: check the logs with `kubectl -n kube-system logs` command
|
||||
|
||||
TODO: important logs
|
||||
|
||||
```
|
||||
2022/11/05 21:38:20 New key written to kube-system/sealed-secrets-keymwzn9
|
||||
2022/11/05 21:38:20 Certificate is
|
||||
-----BEGIN CERTIFICATE-----
|
||||
< cert content >
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
2022/11/05 21:38:20 HTTP server serving on :808
|
||||
```
|
||||
|
||||
TODO: check our secret
|
||||
|
||||
```
|
||||
kubectl get secret -n kube-system sealed-secrets-keymwzn9 -o yaml
|
||||
```
|
||||
|
||||
## Download KubeSeal
|
||||
|
||||
The same way we downloaded the sealed secrets controller from the [GitHub releases](https://github.com/bitnami-labs/sealed-secrets/releases) page,
|
||||
we'll want to download kubeseal from the assets section
|
||||
```
|
||||
|
||||
curl -L -o /tmp/kubeseal.tar.gz \
|
||||
https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.19.1/kubeseal-0.19.1-linux-amd64.tar.gz
|
||||
|
||||
apk add tar
|
||||
tar -xzf /tmp/kubeseal.tar.gz -C /tmp/
|
||||
|
||||
chmod +x /tmp/kubeseal
|
||||
mv /tmp/kubeseal /usr/local/bin/
|
||||
```
|
||||
|
||||
### run kubeseal
|
||||
|
||||
We can now run `kubeseal --help`
|
||||
|
||||
## Sealing a basic Kubernetes Secret
|
||||
|
||||
Looks at our existing Kubernetes secret YAML
|
||||
|
||||
```
|
||||
cat kubernetes/secrets/secret.yaml
|
||||
```
|
||||
|
||||
Create a sealed secret using `stdin`
|
||||
|
||||
```
|
||||
cat kubernetes/secrets/secret.yaml | kubeseal -o yaml > kubernetes/secrets/sealed-secrets/sealed-secret.yaml
|
||||
```
|
||||
|
||||
Create a sealed secret using file
|
||||
|
||||
```
|
||||
kubeseal -f kubernetes/secrets/secret.yaml -o yaml > kubernetes/secrets/sealed-secrets/sealed-secret.yaml
|
||||
```
|
||||
|
||||
Deploy the sealed secret
|
||||
|
||||
```
|
||||
kubectl apply -f kubernetes/secrets/sealed-secrets/sealed-secret.yaml
|
||||
sealedsecret.bitnami.com/mysecret created
|
||||
```
|
||||
|
||||
Now few seconds later, see the secret
|
||||
|
||||
```
|
||||
kubectl -n default get secret
|
||||
NAME TYPE DATA AGE
|
||||
mysecret Opaque 1 25s
|
||||
```
|
||||
|
||||
## How the encryption key is managed
|
||||
|
||||
TODO: How the encryption key is managed and stored
|
||||
|
||||
TODO: Set a duration to test `--key-renew-period=<value>`
|
||||
|
||||
```
|
||||
apk add nano
|
||||
export KUBE_EDITOR=nano
|
||||
```
|
||||
|
||||
Set the flag on the command like so to add a new key every 5 min for testing:
|
||||
|
||||
```
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- controller
|
||||
- --key-renew-period=5m
|
||||
|
||||
kubectl edit deployment/sealed-secrets-controller --namespace=kube-system
|
||||
```
|
||||
|
||||
You should see a new key created under secrets in the `kube-system` namespace
|
||||
|
||||
```
|
||||
kubectl -n kube-system get secrets
|
||||
```
|
||||
|
||||
|
||||
## Backup your encryption keys
|
||||
|
||||
TODO: * backup encryption keys
|
||||
TODO: migrating kubernetes clusters
|
||||
|
||||
```
|
||||
kubectl get secret -n kube-system \
|
||||
-l sealedsecrets.bitnami.com/sealed-secrets-key \
|
||||
-o yaml \
|
||||
> kubernetes/secrets/sealed-secrets/sealed-secret-keys.key
|
||||
```
|
||||
|
||||
## Migrate your encryption keys to a new cluster
|
||||
|
||||
Delete & Deploy a new Kubernetes cluster
|
||||
|
||||
```
|
||||
kind delete cluster --name sealedsecrets
|
||||
kind create cluster --name sealedsecrets --image kindest/node:v1.23.5
|
||||
|
||||
# check the cluster
|
||||
kubectl get nodes
|
||||
|
||||
# redeploy sealed-secrets controller
|
||||
kubectl apply -f kubernetes/secrets/sealed-secrets/controller-v0.19.1.yaml
|
||||
|
||||
kubectl -n kube-system get pods
|
||||
|
||||
```
|
||||
|
||||
### restore our encryption keys
|
||||
|
||||
```
|
||||
kubectl apply -f kubernetes/secrets/sealed-secrets/sealed-secret-keys.key
|
||||
```
|
||||
|
||||
restart the controller:
|
||||
```
|
||||
kubectl delete pod -n kube-system -l name=sealed-secrets-controller
|
||||
```
|
||||
|
||||
### apply our old sealed secret
|
||||
|
||||
```
|
||||
kubectl apply -f kubernetes/secrets/sealed-secrets/sealed-secret.yaml
|
||||
```
|
||||
|
||||
TODO: Encrypted sealed secrets across namespaces https://github.com/bitnami-labs/sealed-secrets#scopes
|
||||
|
||||
## Re-encrypting secrets with the latest key
|
||||
|
||||
```
|
||||
kubeseal --re-encrypt <my_sealed_secret.json >tmp.json \
|
||||
&& mv tmp.json my_sealed_secret.json
|
||||
```
|
354
kubernetes/secrets/sealed-secrets/controller-v0.19.1.yaml
Normal file
354
kubernetes/secrets/sealed-secrets/controller-v0.19.1.yaml
Normal file
@ -0,0 +1,354 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
annotations: {}
|
||||
labels:
|
||||
name: sealed-secrets-controller
|
||||
name: sealed-secrets-controller
|
||||
namespace: kube-system
|
||||
spec:
|
||||
minReadySeconds: 30
|
||||
replicas: 1
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
name: sealed-secrets-controller
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
maxUnavailable: 25%
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
annotations: {}
|
||||
labels:
|
||||
name: sealed-secrets-controller
|
||||
spec:
|
||||
containers:
|
||||
- args: []
|
||||
command:
|
||||
- controller
|
||||
env: []
|
||||
image: docker.io/bitnami/sealed-secrets-controller:v0.19.1
|
||||
imagePullPolicy: IfNotPresent
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http
|
||||
name: sealed-secrets-controller
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http
|
||||
securityContext:
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
stdin: false
|
||||
tty: false
|
||||
volumeMounts:
|
||||
- mountPath: /tmp
|
||||
name: tmp
|
||||
imagePullSecrets: []
|
||||
initContainers: []
|
||||
securityContext:
|
||||
fsGroup: 65534
|
||||
serviceAccountName: sealed-secrets-controller
|
||||
terminationGracePeriodSeconds: 30
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: tmp
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: sealedsecrets.bitnami.com
|
||||
spec:
|
||||
group: bitnami.com
|
||||
names:
|
||||
kind: SealedSecret
|
||||
listKind: SealedSecretList
|
||||
plural: sealedsecrets
|
||||
singular: sealedsecret
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: SealedSecret is the K8s representation of a "sealed Secret" -
|
||||
a regular k8s Secret that has been sealed (encrypted) using the controller's
|
||||
key.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: SealedSecretSpec is the specification of a SealedSecret
|
||||
properties:
|
||||
data:
|
||||
description: Data is deprecated and will be removed eventually. Use
|
||||
per-value EncryptedData instead.
|
||||
format: byte
|
||||
type: string
|
||||
encryptedData:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
template:
|
||||
description: Template defines the structure of the Secret that will
|
||||
be created from this sealed secret.
|
||||
properties:
|
||||
data:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Keys that should be templated using decrypted data
|
||||
nullable: true
|
||||
type: object
|
||||
metadata:
|
||||
description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
|
||||
nullable: true
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type:
|
||||
description: Used to facilitate programmatic handling of secret
|
||||
data.
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- encryptedData
|
||||
type: object
|
||||
status:
|
||||
description: SealedSecretStatus is the most recently observed status of
|
||||
the SealedSecret.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the latest available observations of a sealed
|
||||
secret's current state.
|
||||
items:
|
||||
description: SealedSecretCondition describes the state of a sealed
|
||||
secret at a certain point.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: Last time the condition transitioned from one status
|
||||
to another.
|
||||
format: date-time
|
||||
type: string
|
||||
lastUpdateTime:
|
||||
description: The last time this condition was updated.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: A human readable message indicating details about
|
||||
the transition.
|
||||
type: string
|
||||
reason:
|
||||
description: The reason for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: 'Status of the condition for a sealed secret. Valid
|
||||
values for "Synced": "True", "False", or "Unknown".'
|
||||
type: string
|
||||
type:
|
||||
description: 'Type of condition for a sealed secret. Valid value:
|
||||
"Synced"'
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
observedGeneration:
|
||||
description: ObservedGeneration reflects the generation most recently
|
||||
observed by the sealed-secrets controller.
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
annotations: {}
|
||||
labels:
|
||||
name: sealed-secrets-controller
|
||||
name: sealed-secrets-controller
|
||||
namespace: kube-system
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: sealed-secrets-key-admin
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: sealed-secrets-controller
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
annotations: {}
|
||||
labels:
|
||||
name: sealed-secrets-controller
|
||||
name: sealed-secrets-controller
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations: {}
|
||||
labels:
|
||||
name: sealed-secrets-controller
|
||||
name: sealed-secrets-controller
|
||||
namespace: kube-system
|
||||
spec:
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
name: sealed-secrets-controller
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
annotations: {}
|
||||
labels:
|
||||
name: sealed-secrets-service-proxier
|
||||
name: sealed-secrets-service-proxier
|
||||
namespace: kube-system
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: sealed-secrets-service-proxier
|
||||
subjects:
|
||||
- apiGroup: rbac.authorization.k8s.io
|
||||
kind: Group
|
||||
name: system:authenticated
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
annotations: {}
|
||||
labels:
|
||||
name: sealed-secrets-service-proxier
|
||||
name: sealed-secrets-service-proxier
|
||||
namespace: kube-system
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resourceNames:
|
||||
- sealed-secrets-controller
|
||||
resources:
|
||||
- services
|
||||
verbs:
|
||||
- get
|
||||
- apiGroups:
|
||||
- ""
|
||||
resourceNames:
|
||||
- 'http:sealed-secrets-controller:'
|
||||
- http:sealed-secrets-controller:http
|
||||
- sealed-secrets-controller
|
||||
resources:
|
||||
- services/proxy
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
annotations: {}
|
||||
labels:
|
||||
name: sealed-secrets-key-admin
|
||||
name: sealed-secrets-key-admin
|
||||
namespace: kube-system
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- create
|
||||
- list
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
annotations: {}
|
||||
labels:
|
||||
name: sealed-secrets-controller
|
||||
name: sealed-secrets-controller
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: secrets-unsealer
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: sealed-secrets-controller
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
annotations: {}
|
||||
labels:
|
||||
name: secrets-unsealer
|
||||
name: secrets-unsealer
|
||||
rules:
|
||||
- apiGroups:
|
||||
- bitnami.com
|
||||
resources:
|
||||
- sealedsecrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- bitnami.com
|
||||
resources:
|
||||
- sealedsecrets/status
|
||||
verbs:
|
||||
- update
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- create
|
||||
- update
|
||||
- delete
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- namespaces
|
||||
verbs:
|
||||
- get
|
16
kubernetes/secrets/sealed-secrets/sealed-secret.yaml
Normal file
16
kubernetes/secrets/sealed-secrets/sealed-secret.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
apiVersion: bitnami.com/v1alpha1
|
||||
kind: SealedSecret
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: mysecret
|
||||
namespace: default
|
||||
spec:
|
||||
encryptedData:
|
||||
secret.json: AgBic1vT0+Y9WcUY3GqOlX+Zjstl7IDEY/U/XOykbRXGtUo6kgAG7Bkq/CyoXqDaNKD+4UhRpd9LZUw/6pvMpAjqsgSQw0ZBaALivxyZ7xSJ3/CpfsLlatWQoVWsnIoY8s0VW0eKhKPq0t30sNJSghH9yni3dgvBI3cyS1Xe2s9A7m/eUqUJqa82UE5y1UuRTRNiSUPmAVCaaW1md6K17DB9V7TE4mQn23IYF/xxSjjEhYFwsra2d7AXvSJiY63mHKRltQ6NxzJGA7xpvJTPV2MY1YIz8wsyKk8gQ2WZnnJrNGCoRlkE3hw2ZUFJGrivlWogcVYDL8EW8ngEEGdrhAbbTwzV17GDVt4rqgk6ag37yXL5rc01YD6BVTDGLglb59sRtRNkHAFr8GZmawVosswjRRDNHhzemgmpI2sOAn/ftvM5bjBNStnLBXAvOrh6sKDAiC2hERYegSjc/dwa9sdKI095lOduNXk55HorlyfiJ6bSV7h9Qc/A6P/whjL1YkZ+3iZA2b2DLEOWPSbaRhUYv4vfwkk3Abis3olXfI1dKwRec039AibhSeE/8FcrAik21XScWXT/QEH80yq6fzOUTMQRXLRzx7XRHfawEt6Oz5WV8mmR/XwueYx6Hw/SG8hxx6UUQqPaS66xVJgyL0g2EwonjLEtNQc+5/xrhaWAqyyRoeCB+2da5ZSUYWVhYdw99XNeg9HQ5mQpdPjMBW0/83gG2ZIr8XPgoo3OalYD5vwL4Q8drw==
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: mysecret
|
||||
namespace: default
|
||||
type: Opaque
|
||||
|
Loading…
x
Reference in New Issue
Block a user