mirror of
https://github.com/plankanban/planka.git
synced 2026-03-01 11:21:46 +03:00
feat(helm): Add image digest pinning support (#1531)
* feat(helm): add image digest field to values - Add optional 'digest' field under image.repository configuration - Allows users to pin container images by SHA256 digest - Improves security through immutable image identification - Fully backward compatible (digest is optional) * feat(helm): implement image digest pinning in deployment template - Add conditional logic to support SHA256 digest in image references - When digest is set with tag: generates 'repository:tag@sha256:digest' - When digest is set without tag: generates 'repository@sha256:digest' - Preserves backward compatibility with tag-only deployments - Validates tag presence to avoid invalid image references * docs(helm): add image digest pinning documentation - Add 'Image Digest Pinning' section under Advanced Configuration - Include methods for finding image digests (docker inspect, skopeo) - Document two usage options: - Option 1: Digest with tag (recommended) for reference + verification - Option 2: Digest only for minimalist configuration - Explain security benefits (immutability, supply chain security, reproducibility) - Provide complete helm and values.yaml examples
This commit is contained in:
@@ -68,7 +68,7 @@ helm install planka . --set secretkey=$SECRETKEY \
|
||||
|
||||
or create a values.yaml file like:
|
||||
|
||||
```yaml
|
||||
````yaml
|
||||
secretkey: "<InsertSecretKey>"
|
||||
# The admin section needs to be present for new instances of PLANKA, after the first start you can remove the lines starting with admin_. If you want the admin user to be unchangeable admin_email: has to stay
|
||||
# After changing the config you have to run ```helm upgrade planka . -f values.yaml```
|
||||
@@ -89,11 +89,11 @@ ingress:
|
||||
- path: /
|
||||
pathType: ImplementationSpecific
|
||||
|
||||
# Needed for HTTPS
|
||||
# Needed for HTTPS
|
||||
tls:
|
||||
- secretName: planka-tls # existing TLS secret in k8s
|
||||
hosts:
|
||||
- planka.example.dev
|
||||
- secretName: planka-tls # existing TLS secret in k8s
|
||||
hosts:
|
||||
- planka.example.dev
|
||||
```
|
||||
|
||||
```bash
|
||||
@@ -135,14 +135,14 @@ extraMounts:
|
||||
subPath: ca.crt
|
||||
readOnly: true
|
||||
configMap:
|
||||
name: ca-certificates # Must exist
|
||||
name: ca-certificates # Must exist
|
||||
|
||||
# Mount TLS certificates from existing Secret
|
||||
- name: tls-certs
|
||||
mountPath: /etc/ssl/private
|
||||
readOnly: true
|
||||
secret:
|
||||
secretName: planka-tls-secret # Must exist
|
||||
secretName: planka-tls-secret # Must exist
|
||||
items:
|
||||
- key: tls.crt
|
||||
path: server.crt
|
||||
@@ -178,11 +178,13 @@ extraMounts:
|
||||
A common use case is configuring OIDC with a self-hosted Keycloak instance that uses custom CA certificates.
|
||||
|
||||
First, create the CA certificate ConfigMap:
|
||||
|
||||
```bash
|
||||
kubectl create configmap ca-certificates --from-file=ca.crt=/path/to/your/ca.crt
|
||||
```
|
||||
|
||||
Then configure the chart:
|
||||
|
||||
```yaml
|
||||
# Mount custom CA certificate from existing ConfigMap
|
||||
extraMounts:
|
||||
@@ -225,6 +227,67 @@ extraEnv:
|
||||
key: api-key
|
||||
```
|
||||
|
||||
### Image Digest Pinning
|
||||
|
||||
For enhanced security and reproducibility, you can pin the container image using its SHA256 digest instead of relying solely on tags. This ensures you always deploy the exact same image, preventing tag mutations or accidental updates.
|
||||
|
||||
#### Finding the Image Digest
|
||||
|
||||
You can find the digest of a specific image tag using:
|
||||
|
||||
```bash
|
||||
docker inspect ghcr.io/plankanban/planka:latest --format='{{index .RepoDigests 0}}'
|
||||
# Output: ghcr.io/plankanban/planka@sha256:abc123def456...
|
||||
|
||||
# Or with skopeo
|
||||
skopeo inspect docker://ghcr.io/plankanban/planka:latest
|
||||
```
|
||||
|
||||
#### Usage
|
||||
|
||||
You can use digest pinning in several ways:
|
||||
|
||||
**Option 1: Digest with tag (recommended)**
|
||||
|
||||
Includes the tag for reference while using the digest for verification:
|
||||
|
||||
```bash
|
||||
helm install planka . --set secretkey=$SECRETKEY \
|
||||
--set image.tag=latest \
|
||||
--set image.digest=abc123def456... \
|
||||
--set admin_email="demo@demo.demo" \
|
||||
--set admin_password="demo" \
|
||||
--set admin_name="Demo Demo" \
|
||||
--set admin_username="demo"
|
||||
```
|
||||
|
||||
Or in values.yaml:
|
||||
|
||||
```yaml
|
||||
image:
|
||||
repository: ghcr.io/plankanban/planka
|
||||
tag: latest
|
||||
digest: "abc123def456ab89cd12ef34ab56cd78ef90ab12cd34ef56ab78cd90ef12ab34"
|
||||
```
|
||||
|
||||
**Option 2: Digest only**
|
||||
|
||||
If you prefer to pin only by digest without specifying a tag:
|
||||
|
||||
```yaml
|
||||
image:
|
||||
repository: ghcr.io/plankanban/planka
|
||||
tag: "" # Empty - digest alone identifies the image
|
||||
digest: "abc123def456ab89cd12ef34ab56cd78ef90ab12cd34ef56ab78cd90ef12ab34"
|
||||
```
|
||||
|
||||
#### Security Benefits
|
||||
|
||||
- **Immutability**: Ensures you always deploy the exact same image
|
||||
- **Supply Chain Security**: Protects against tag mutations or registry compromise
|
||||
- **Reproducibility**: Makes deployments fully reproducible across environments
|
||||
- **Audit Trail**: Provides clear image identity in deployment manifests
|
||||
|
||||
### Complete Example
|
||||
|
||||
See `values-example.yaml` for a comprehensive example that demonstrates all the advanced features including OIDC configuration with custom CA certificates.
|
||||
|
||||
@@ -39,7 +39,16 @@ spec:
|
||||
- name: {{ .Chart.Name }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
{{- $imageTag := .Values.image.tag | default .Chart.AppVersion }}
|
||||
{{- if .Values.image.digest }}
|
||||
{{- if $imageTag }}
|
||||
image: "{{ .Values.image.repository }}:{{ $imageTag }}@sha256:{{ .Values.image.digest }}"
|
||||
{{- else }}
|
||||
image: "{{ .Values.image.repository }}@sha256:{{ .Values.image.digest }}"
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
image: "{{ .Values.image.repository }}:{{ $imageTag }}"
|
||||
{{- end }}
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
|
||||
@@ -9,6 +9,10 @@ image:
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: ""
|
||||
# Optional: specify the image digest for pinning by SHA256
|
||||
# When set, the image reference will include the digest for enhanced security
|
||||
# Example: "abc123def456..." (without sha256: prefix)
|
||||
digest: ""
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ""
|
||||
|
||||
Reference in New Issue
Block a user