diff --git a/README.md b/README.md new file mode 100644 index 0000000..6435e5f --- /dev/null +++ b/README.md @@ -0,0 +1,104 @@ +Helmule + +This tool is not production ready yet, I'm still changing the config format, so don't rely on it for a time being. + +# What it's supposed to do? + +It would be just a yet another tool to mirror helm charts, but there is a couple of features that (I hope) are making this tool special. So let's go through all of them. + +So, let's imaging you need to mirror a helm chart for whatever reason. Maybe you just don't trust original authors that much, or you use ArgoCD ~~~that doesn't know what is helm and how it's supposed to be used~~~, or whatever else. We'll start by a simple mirroring and then walk through all features later. + +First we create a config file + +```yaml +repositories: {} +charts: {} +mirrors: {} +``` + +Currently there are two types of mirrors that are supported: +- Git +- Custom Comand + + +Let's start with git. + +```yaml +# Basic example +mirrors: + - name: my-git-mirror + git: + url: git@git.badhouseplants.net:allanger/helmuled-charts.git + branch: mirror-something + path: charts/something + commit: |- + chore: mirror something + +``` + +As you can see, it won't work on scale, so all the field can be templated using the chart data and a couple of helpers. + +```yaml + - name: badhouseplants-git + git: + url: git@git.badhouseplants.net:allanger/helmuled-charts.git + branch: upgrade-{{ name }}-to-{{ version }} + path: charts/{{ name }} + commit: |- + chore: mirror {{ name }}-{{ version }} + + upstream_repo: {{ repo_url }} +``` + +It can be scaled better already. URL can also be templated, and there is special property for variables, that you can also use here + +```yaml +variables: + git-msg: Hello there + +mirrors: + - name: badhouseplants-git + git: + url: git@git.badhouseplants.net:allanger/helmuled-charts.git + branch: upgrade-{{ name }}-to-{{ version }} + path: charts/{{ name }} + commit: |- + chore: mirror {{ name }}-{{ version }} + {{ vars.git-msg }} + upstream_repo: {{ repo_url }} +``` + +Currently, there are two available helpers: +- date: `{{ date }}` +- time: `{{ time }}` + +Also you can provide `rebase` and `default_branch`, if you want helmiule to rebase before pushing. + +That would be it for git, and now the second option: CustomCommand + +The process of mirroring is split into two parts: +- Package +- Upload + +The second is being executed only if you don't run in the `dry-run` mode. Git mirror handles it in code. But for custom command you'll have to define it yourself. Just check the following example: + +```yaml +mirrors: + - name: custom-command + custom_command: + package: + - zip -r {{ name }}-{{ version }}.zip {{ name }}-{{ version }} + upload: + - rm -f /tmp/{{ name }}-{{ version }}.zip + - rm -rf /tmp/{{ name }}-{{ version }} + - cp {{ name }}-{{ version }}.zip /tmp + - unzip /tmp/{{ name }}-{{ version }}.zip -d /tmp/{{ name }}-{{ version}} +``` + +These command are executed from the workdir. It's created during the run, and by default it's using a library to create a temporary directory, but you also can chose one by providing the `-w/--workdir` flag. Run will fail if this folder exists though, because it's expected to be created by helmule. + +Now, when we got our mirrors, we need to start mirroring. + +...to be continued... + + diff --git a/examples/giantswarm/charts/external-secrets-operator.yaml b/examples/giantswarm/charts/external-secrets-operator.yaml new file mode 100644 index 0000000..5e6253a --- /dev/null +++ b/examples/giantswarm/charts/external-secrets-operator.yaml @@ -0,0 +1,7 @@ +name: external-secrets +repository: external-secrets +variables: + target_repo: app-external-secrets-operator +version: 0.8.3 +mirrors: + - apps-git diff --git a/examples/giantswarm/charts/gitops-server.yaml b/examples/giantswarm/charts/gitops-server.yaml new file mode 100644 index 0000000..f7e053a --- /dev/null +++ b/examples/giantswarm/charts/gitops-server.yaml @@ -0,0 +1,61 @@ +# ------------------------------------------------------------------- +# -- GitOps Server Application +# ------------------------------------------------------------------- +- name: weave-gitops + repository: weave + version: 4.0.15 + variables: + target_repo: app-gitops-server + mirrors: + - apps-git + extensions: + - name: Add VPA + source_dir: ../extensions/vpa-gitops-server + target_dir: templates/gs-vpa + patches: + - name: Git patch + git: + path: ../patches/git/gitops-server.patch + - name: Generate values.schema + custom_command: + commands: + - helm schema-gen values.yaml > values.schema.json + - name: Git patch for values schema + git: + path: ../patches/git/gitops-server-values-schema.patch + - name: Git patch for test-job security + git: + path: ../patches/git/gitops-server-test-job.patch + # -- Update Chart.ymal + #- name: Change the chart name + # yq: + # op: Replace + # file: Chart.yaml + # key: .name + # value: gitops-server + - name: Set the home URL + yq: + op: Add + file: Chart.yaml + key: .home + value: https://github.com/giantswarm/gitops-server-app + - name: set the icon url + yq: + op: Add + file: Chart.yaml + key: .icon + value: https://s.giantswarm.io/app-icons/weaveworks/1/icon_light.svg + - name: Add keywords + yq: + op: Add + file: Chart.yaml + key: .keywords + value: '["gitops", "flux"]' + - name: team annotation + - name: gs version + yq: + op: Add + key: .annotations."config.giantswarm.io/version" + value: 1.x.x + file: Chart.yaml + - name: yamlfmt diff --git a/examples/giantswarm/charts/zot.yaml b/examples/giantswarm/charts/zot.yaml new file mode 100644 index 0000000..3b17f9b --- /dev/null +++ b/examples/giantswarm/charts/zot.yaml @@ -0,0 +1,24 @@ +# ------------------------------------------------------------------- +# -- Zot Application +# ------------------------------------------------------------------- +name: zot +repository: zot-git +extensions: + - name: Add VPA + source_dir: ../extensions/vpa + target_dir: templates/gs-vpa + - name: Add values for CI + source_dir: ../extensions/ci-values + target_dir: ci +variables: + target_repo: zot-app +patches: + - name: team annotation + - name: set home + - name: set engine + - name: yamlfmt + - name: Git patch + git: + path: ../patches/git/zot.patch +mirrors: + - apps-git diff --git a/examples/giantswarm/extensions/ci-values/values-vpa.yaml b/examples/giantswarm/extensions/ci-values/values-vpa.yaml new file mode 100644 index 0000000..34c4089 --- /dev/null +++ b/examples/giantswarm/extensions/ci-values/values-vpa.yaml @@ -0,0 +1,9 @@ +resources: + requests: + memory: 100Mi + cpu: 70m + limits: + memory: 700Mi + cpu: 400m +vpa: + enabled: true diff --git a/examples/giantswarm/extensions/vpa-gitops-server/vpa.yaml b/examples/giantswarm/extensions/vpa-gitops-server/vpa.yaml new file mode 100644 index 0000000..e5ee491 --- /dev/null +++ b/examples/giantswarm/extensions/vpa-gitops-server/vpa.yaml @@ -0,0 +1,27 @@ +{{ if eq (include "resource.vpa.enabled" .) "true" }} +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: gitops-server + namespace: {{ .Release.Namespace }} + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + resourcePolicy: + containerPolicies: + - containerName: {{ .Chart.Name }} + controlledValues: RequestsAndLimits + minAllowed: + cpu: {{ .Values.giantswarm.resources.server.requests.cpu }} + memory: {{ .Values.giantswarm.resources.server.requests.memory }} + maxAllowed: + cpu: 1000m + memory: 1000Mi + mode: Auto + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "chart.fullname" . }} + updatePolicy: + updateMode: Auto +{{ end }} diff --git a/examples/giantswarm/extensions/vpa/_helpers.tpl b/examples/giantswarm/extensions/vpa/_helpers.tpl new file mode 100644 index 0000000..b4c3802 --- /dev/null +++ b/examples/giantswarm/extensions/vpa/_helpers.tpl @@ -0,0 +1,51 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "chart.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 "chart.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 "chart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "chart.labels" -}} +helm.sh/chart: {{ include "chart.chart" . }} +{{ include "chart.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "chart.selectorLabels" -}} +app.kubernetes.io/name: {{ include "chart.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/examples/giantswarm/extensions/vpa/vpa.yaml b/examples/giantswarm/extensions/vpa/vpa.yaml new file mode 100644 index 0000000..67a3584 --- /dev/null +++ b/examples/giantswarm/extensions/vpa/vpa.yaml @@ -0,0 +1,29 @@ +{{ if (.Values.vpa).enabled }} +{{ if .Values.resources }} +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: {{ include "chart.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + resourcePolicy: + containerPolicies: + - containerName: manager + controlledValues: RequestsAndLimits + minAllowed: + cpu: {{ .Values.resources.requests.cpu }} + memory: {{ .Values.resources.requests.memory }} + maxAllowed: + cpu: {{ .Values.resources.limits.cpu }} + memory: {{ .Values.resources.limits.memory }} + mode: Auto + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "chart.fullname" . }} + updatePolicy: + updateMode: Auto +{{- end }} +{{- end }} diff --git a/examples/giantswarm/helmule.yaml b/examples/giantswarm/helmule.yaml new file mode 100644 index 0000000..b043daf --- /dev/null +++ b/examples/giantswarm/helmule.yaml @@ -0,0 +1,59 @@ +variables: + global: example + +include: + - kind: Charts + path: ./charts/zot.yaml + - kind: Charts + path: ./charts/gitops-server.yaml + - kind: Charts + path: ./charts/external-secrets-operator.yaml +patches: + - name: yamlfmt + custom_command: + commands: + - "cat <> .yamlfmt\n formatter:\n pad_line_comments: 2\nEOT" + - yamlfmt values.yaml --conf ./yamlfmt.yaml + - rm -f yamlfmt.yaml + - name: team annotation + yq: + op: Add + key: .annotations."application.giantswarm.io/team" + value: team-honeybadger + file: Chart.yaml + - name: set home + yq: + op: Add + key: .home + value: https://github.com/giantswarm/flux-app + file: Chart.yaml + - name: set engine + yq: + op: Add + key: .engine + value: gtpl + file: Chart.yaml +repositories: + # -- Because their helm repo seems not to be accessible + - name: zot-git + git: + url: https://github.com/project-zot/helm-charts.git + git_ref: main + # git_ref: zot-0.1.42 + path: charts + - name: weave + helm: + url: https://helm.gitops.weave.works + - name: external-secrets + helm: + url: https://charts.external-secrets.io +mirrors: + - name: apps-git + git: + url: git@git.badhouseplants.net:allanger/{{ vars.target_repo }}.git + git_dir: app-{{ name }}-git + branch: upgrade-{{ name }}-to-{{ version }} + path: helm/{{ name }} + commit: |- + chore: mirror {{ name }}-{{ version }} + upstream_repo: {{ repo_url }} diff --git a/examples/giantswarm/patches/git/gitops-server-test-job.patch b/examples/giantswarm/patches/git/gitops-server-test-job.patch new file mode 100644 index 0000000..ce9ff68 --- /dev/null +++ b/examples/giantswarm/patches/git/gitops-server-test-job.patch @@ -0,0 +1,19 @@ +diff --git a/templates/tests/test-connection.yaml b/templates/tests/test-connection.yaml +index 8dfed87..b4b98bc 100644 +--- a/templates/tests/test-connection.yaml ++++ b/templates/tests/test-connection.yaml +@@ -9,7 +9,13 @@ metadata: + spec: + containers: + - name: wget +- image: busybox ++ image: "{{ .Values.image.registry }}/{{ .Values.giantswarm.images.test.image }}:{{ .Values.giantswarm.images.test.tag }}" ++ imagePullPolicy: {{ .Values.giantswarm.images.test.pullPolicy }} + command: ['wget'] + args: ['{{ include "chart.fullname" . }}:{{ .Values.service.port }}'] ++ securityContext: ++ readOnlyRootFilesystem: true ++ runAsUser: 1000 ++ resources: ++ {{- toYaml .Values.giantswarm.resources.test | nindent 8 }} + restartPolicy: Never diff --git a/examples/giantswarm/patches/git/gitops-server-values-schema.patch b/examples/giantswarm/patches/git/gitops-server-values-schema.patch new file mode 100644 index 0000000..aa6ad53 --- /dev/null +++ b/examples/giantswarm/patches/git/gitops-server-values-schema.patch @@ -0,0 +1,210 @@ +diff --git a/values.schema.json b/values.schema.json +index f759f82..c0762fa 100644 +--- a/values.schema.json ++++ b/values.schema.json +@@ -43,10 +43,51 @@ + } + }, + "extraVolumeMounts": { +- "type": "array" ++ "type": "array", ++ "items": { ++ "type": "object", ++ "properties": { ++ "mountPath": { ++ "type": "string" ++ }, ++ "name": { ++ "type": "string" ++ }, ++ "readOnly": { ++ "type": "boolean" ++ } ++ } ++ } + }, + "extraVolumes": { +- "type": "array" ++ "type": "array", ++ "items": { ++ "type": "object", ++ "properties": { ++ "csi": { ++ "type": "object", ++ "properties": { ++ "driver": { ++ "type": "string" ++ }, ++ "readOnly": { ++ "type": "boolean" ++ }, ++ "volumeAttributes": { ++ "type": "object", ++ "properties": { ++ "secretProviderClass": { ++ "type": "string" ++ } ++ } ++ } ++ } ++ }, ++ "name": { ++ "type": "string" ++ } ++ } ++ } + }, + "fullnameOverride": { + "type": "string" +@@ -91,7 +132,30 @@ + "type": "object", + "properties": { + "additionalRules": { +- "type": "array" ++ "type": "array", ++ "items": { ++ "type": "object", ++ "properties": { ++ "apiGroups": { ++ "type": "array", ++ "items": { ++ "type": "string" ++ } ++ }, ++ "resources": { ++ "type": "array", ++ "items": { ++ "type": "string" ++ } ++ }, ++ "verbs": { ++ "type": "array", ++ "items": { ++ "type": "string" ++ } ++ } ++ } ++ } + }, + "create": { + "type": "boolean" +@@ -106,7 +170,10 @@ + "type": "boolean" + }, + "resourceNames": { +- "type": "array" ++ "type": "array", ++ "items": { ++ "type": "string" ++ } + } + } + }, +@@ -117,7 +184,10 @@ + "type": "boolean" + }, + "resourceNames": { +- "type": "array" ++ "type": "array", ++ "items": { ++ "type": "string" ++ } + } + } + } +@@ -134,6 +204,14 @@ + "resources": { + "type": "object", + "properties": { ++ "vpa":{ ++ "type": "object", ++ "properties": { ++ "enabled": { ++ "type": "boolean" ++ } ++ } ++ }, + "server": { + "type": "object", + "properties": { +@@ -187,14 +265,6 @@ + } + } + } +- }, +- "vpa": { +- "type": "object", +- "properties": { +- "enabled": { +- "type": "boolean" +- } +- } + } + } + } +@@ -209,7 +279,15 @@ + } + }, + "imagePullSecrets": { +- "type": "array" ++ "type": "array", ++ "items": { ++ "type": "object", ++ "properties": { ++ "name": { ++ "type": "string" ++ } ++ } ++ } + }, + "ingress": { + "type": "object", +@@ -224,10 +302,46 @@ + "type": "boolean" + }, + "hosts": { +- "type": "array" ++ "type": "array", ++ "items": { ++ "type": "object", ++ "properties": { ++ "host": { ++ "type": "string" ++ }, ++ "paths": { ++ "type": "array", ++ "items": { ++ "type": "object", ++ "properties": { ++ "path": { ++ "type": "string" ++ }, ++ "pathType": { ++ "type": "string" ++ } ++ } ++ } ++ } ++ } ++ } + }, + "tls": { +- "type": "array" ++ "type": "array", ++ "items": { ++ "type": "object", ++ "properties": { ++ "hosts": { ++ "type": "array", ++ "items": { ++ "type": "string" ++ } ++ }, ++ "secretName": { ++ "type": "string" ++ } ++ } ++ } + } + } + }, diff --git a/examples/giantswarm/patches/git/gitops-server.patch b/examples/giantswarm/patches/git/gitops-server.patch new file mode 100644 index 0000000..5540cfc --- /dev/null +++ b/examples/giantswarm/patches/git/gitops-server.patch @@ -0,0 +1,307 @@ +diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl +index af32c5b..1fdf723 100644 +--- a/templates/_helpers.tpl ++++ b/templates/_helpers.tpl +@@ -39,6 +39,7 @@ helm.sh/chart: {{ include "chart.chart" . }} + {{- if .Chart.AppVersion }} + app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} + {{- end }} ++application.giantswarm.io/team: {{ index .Chart.Annotations "application.giantswarm.io/team" | quote }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- end }} + +@@ -75,3 +76,16 @@ Return the target Kubernetes version + {{- default .Capabilities.KubeVersion.Version .Values.kubeVersion -}} + {{- end -}} + {{- end -}} ++ ++{{- define "resource.vpa.enabled" -}} ++{{- if and (.Capabilities.APIVersions.Has "autoscaling.k8s.io/v1") (.Values.giantswarm.resources.vpa.enabled) }}true{{ else }}false{{ end }} ++{{- end -}} ++ ++{{- define "deployment.resources" -}} ++requests: ++{{ toYaml .Values.giantswarm.resources.server.requests | indent 2 -}} ++{{ if eq (include "resource.vpa.enabled" .) "false" }} ++limits: ++{{ toYaml .Values.giantswarm.resources.server.limits | indent 2 -}} ++{{- end -}} ++{{- end -}} +diff --git a/templates/admin-user-roles.yaml b/templates/admin-user-roles.yaml +index 74a1844..c0fa72c 100644 +--- a/templates/admin-user-roles.yaml ++++ b/templates/admin-user-roles.yaml +@@ -30,8 +30,8 @@ rules: + resources: ["terraforms"] + verbs: [ "get", "list", "watch", "patch" ] + +-{{- if gt (len $.Values.rbac.additionalRules) 0 -}} +-{{- toYaml $.Values.rbac.additionalRules | nindent 2 -}} ++{{- if gt (len $.Values.giantswarm.rbac.additionalRules) 0 -}} ++{{- toYaml $.Values.giantswarm.rbac.additionalRules | nindent 2 -}} + {{- end }} + {{- if .Values.adminUser.createClusterRole }} + --- +@@ -72,8 +72,8 @@ rules: + resources: [ "providers", "alerts" ] + verbs: [ "get", "list", "watch", "patch" ] + +-{{- if gt (len $.Values.rbac.additionalRules) 0 -}} +-{{- toYaml $.Values.rbac.additionalRules | nindent 2 -}} ++{{- if gt (len $.Values.giantswarm.rbac.additionalRules) 0 -}} ++{{- toYaml $.Values.giantswarm.rbac.additionalRules | nindent 2 -}} + {{- end -}} + {{- end }} + {{- end }} +diff --git a/templates/deployment.yaml b/templates/deployment.yaml +index a54c37c..a498259 100644 +--- a/templates/deployment.yaml ++++ b/templates/deployment.yaml +@@ -36,8 +36,8 @@ spec: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} +- image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" +- imagePullPolicy: {{ .Values.image.pullPolicy }} ++ image: "{{ .Values.image.registry }}/{{ .Values.giantswarm.images.server.image }}:{{ .Values.giantswarm.images.server.tag | default .Chart.AppVersion }}" ++ imagePullPolicy: {{ .Values.giantswarm.images.server.pullPolicy }} + args: + - "--log-level" + - "{{ .Values.logLevel }}" +@@ -88,7 +88,7 @@ spec: + {{- end }} + {{- end }} + resources: +- {{- toYaml .Values.resources | nindent 12 }} ++ {{- include "deployment.resources" . | nindent 12 }} + {{- if or .Values.serverTLS.enable .Values.extraVolumeMounts }} + volumeMounts: + {{- end }} +diff --git a/templates/role.yaml b/templates/role.yaml +index b292176..5a55339 100644 +--- a/templates/role.yaml ++++ b/templates/role.yaml +@@ -1,4 +1,4 @@ +-{{- if .Values.rbac.create -}} ++{{- if .Values.giantswarm.rbac.create -}} + {{- if semverCompare "<1.17-0" (include "common.capabilities.kubeVersion" .) -}} + apiVersion: rbac.authorization.k8s.io/v1beta1 + {{- else }} +@@ -6,32 +6,39 @@ apiVersion: rbac.authorization.k8s.io/v1 + {{- end }} + kind: ClusterRole + metadata: +- name: {{ include "chart.fullname" . }} ++ name: {{ include "chart.fullname" . }} + rules: + # impersonation rules for ui calls ++ {{- if .Values.giantswarm.rbac.impersonation.users.enabled }} + - apiGroups: [""] +- resources: {{ .Values.rbac.impersonationResources | toJson }} ++ resources: ["users"] + verbs: [ "impersonate" ] +- {{- with .Values.rbac.impersonationResourceNames }} ++ {{- with .Values.giantswarm.rbac.impersonation.users.resourceNames }} + resourceNames: {{ . | toJson }} + {{- end }} ++ {{- end }} ++ {{- if .Values.giantswarm.rbac.impersonation.groups.enabled }} ++ {{- if and .Values.giantswarm.rbac.impersonation.groups.enabled (not .Values.giantswarm.rbac.impersonation.users.enabled) }} ++ {{- fail "Enabling impersonation for groups requires users impersonation permissions, see https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation" }} ++ {{- end }} ++ - apiGroups: [""] ++ resources: ["groups"] ++ verbs: [ "impersonate" ] ++ {{- with .Values.giantswarm.rbac.impersonation.groups.resourceNames }} ++ resourceNames: {{ . | toJson }} ++ {{- end }} ++ {{- end }} + # Access to enterprise entitlement + - apiGroups: [""] + resources: [ "secrets" ] + verbs: [ "get", "list" ] +- {{- if and .Values.rbac.viewSecrets .Values.rbac.viewSecretsResourceNames }} +- {{- fail "You've supplied both rbac.viewSecrets and rbac.viewSecretsResourceNames. Please only use rbac.viewSecretsResourceNames" }} +- {{- end }} +- # or should return the first non-falsy result +- {{- with (or .Values.rbac.viewSecretsResourceNames .Values.rbac.viewSecrets) }} ++ {{- with .Values.giantswarm.rbac.viewSecretsResourceNames }} + resourceNames: {{ . | toJson }} + {{- end }} +- + # The service account needs to read namespaces to know where it can query + - apiGroups: [ "" ] + resources: [ "namespaces" ] + verbs: [ "get", "list", "watch" ] +- + # The service account needs to list custom resources to query if given feature + # is available or not. + - apiGroups: [ "apiextensions.k8s.io" ] +diff --git a/templates/rolebinding.yaml b/templates/rolebinding.yaml +index b8756fe..df718ff 100644 +--- a/templates/rolebinding.yaml ++++ b/templates/rolebinding.yaml +@@ -1,4 +1,4 @@ +-{{- if .Values.rbac.create -}} ++{{- if .Values.giantswarm.rbac.create -}} + {{- if semverCompare "<1.17-0" (include "common.capabilities.kubeVersion" .) -}} + apiVersion: rbac.authorization.k8s.io/v1beta1 + {{- else }} +@@ -9,7 +9,7 @@ metadata: + name: {{ include "chart.fullname" . }} + labels: + {{- include "chart.labels" . | nindent 4 }} +- {{- with .Values.rbac.annotations }} ++ {{- with .Values.giantswarm.rbac.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +diff --git a/values.yaml b/values.yaml +index 374ad32..7b3b35f 100644 +--- a/values.yaml ++++ b/values.yaml +@@ -1,16 +1,57 @@ +-# Default values for chart. +-# This is a YAML-formatted file. +-# Declare variables to be passed into your templates. ++giantswarm: ++ images: ++ server: ++ image: giantswarm/weaveworks-wego-app ++ pullPolicy: IfNotPresent ++ tag: v0.18.0 ++ test: ++ image: giantswarm/busybox ++ pullPolicy: IfNotPresent ++ tag: 1.36.0 ++ resources: ++ vpa: ++ enabled: true ++ server: ++ limits: ++ cpu: 200m ++ memory: 256Mi ++ requests: ++ cpu: 100m ++ memory: 128Mi ++ test: ++ requests: ++ cpu: 10m ++ memory: 2Mi ++ limits: ++ cpu: 10m ++ memory: 4Mi ++ rbac: ++ create: true ++ impersonation: ++ users: ++ enabled: true ++ # -- If non-empty, this limits the users names that the service account ++ # can impersonate, e.g. `['user1@corporation.com', 'user2@corporation.com']` ++ resourceNames: [] ++ groups: ++ enabled: true ++ # -- If non-empty, this limits the groups names that the service account ++ # can impersonate, e.g. `['admins', 'operations', 'devops']` ++ resourceNames: [] ++ # -- If non-empty, this limits the secrets that can be accessed by ++ # the service account to the specified ones, e.g. `['weave-gitops-enterprise-credentials']` ++ viewSecretsResourceNames: ["cluster-user-auth", "oidc-auth"] ++ # -- If non-empty, these additional rules will be appended to the RBAC role and the cluster role. ++ # for example, ++ # additionalRules: ++ # - apiGroups: ["infra.contrib.fluxcd.io"] ++ # resources: ["terraforms"] ++ # verbs: [ "get", "list", "patch" ] ++ additionalRules: [] + +-# Note: paragraphs starting with `# --` will end up in our manual - +-# see https://github.com/norwoodj/helm-docs + replicaCount: 1 + image: +- # FIXME check the app name +- repository: ghcr.io/weaveworks/wego-app +- pullPolicy: IfNotPresent +- # Overrides the image tag whose default is the chart appVersion. +- tag: "v0.18.0" ++ registry: gsoci.azurecr.io + imagePullSecrets: [] + nameOverride: "" + fullnameOverride: "" +@@ -43,28 +84,9 @@ serviceAccount: + # -- The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" +-rbac: +- # -- Specifies whether the clusterRole & binding to the service account should be created +- create: true +- # -- If non-empty, this limits the resources that the service +- # account can impersonate. This applies to both users and groups, e.g. +- # `['user1@corporation.com', 'user2@corporation.com', 'operations']` +- impersonationResourceNames: [] +- # -- Limit the type of principal that can be impersonated +- impersonationResources: ["users", "groups"] +- # -- If non-empty, this limits the secrets that can be accessed by +- # the service account to the specified ones, e.g. `['weave-gitops-enterprise-credentials']` +- viewSecretsResourceNames: ["cluster-user-auth", "oidc-auth"] +- # -- If non-empty, these additional rules will be appended to the RBAC role and the cluster role. +- # for example, +- # additionalRules: +- # - apiGroups: ["infra.contrib.fluxcd.io"] +- # resources: ["terraforms"] +- # verbs: [ "get", "list", "patch" ] +- additionalRules: [] + adminUser: + # -- Whether the local admin user should be created. +- # If you use this make sure you add it to `rbac.impersonationResourceNames`. ++ # If you use this make sure you add it to `giantswarm.rbac.impersonation.users.resourceNames`. + create: false + # -- Specifies whether the clusterRole & binding to the admin user should be created. + # Will be created only if `adminUser.create` is enabled. Without this, +@@ -82,7 +104,7 @@ adminUser: + # -- (string) Set the password for local admin user. Requires `adminUser.create` and `adminUser.createSecret` + # This needs to have been hashed using bcrypt. + # You can do this via our CLI with `gitops get bcrypt-hash`. +- passwordHash: ++ passwordHash: "" + podAnnotations: {} + podLabels: {} + # aadpodidbinding: identity +@@ -111,7 +133,7 @@ ingress: + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" +- hosts: ++ hosts: [] + # - host: chart-example.local + # paths: + # - path: / +@@ -123,8 +145,8 @@ ingress: + # - chart-example.local + extraVolumes: [] + extraVolumeMounts: [] +-# Example using extraVolumes and extraVolumeMounts to load 'oidc-auth' secret +-# with a secrets store CSI driver. Specify the secretName 'oidc-auth' in the ++# Example using extraVolumes and extraVolumeMounts to load 'oidc-auth' secret ++# with a secrets store CSI driver. Specify the secretName 'oidc-auth' in the + # secretProviderClass so this will be created by the secrets store CSI driver. + # See https://secrets-store-csi-driver.sigs.k8s.io/topics/sync-as-kubernetes-secret.html + # extraVolumeMounts: +@@ -138,17 +160,6 @@ extraVolumeMounts: [] + # readOnly: true + # volumeAttributes: + # secretProviderClass: ww-gitops-oauth-provider +-resources: {} +-# We usually recommend not to specify default resources and to leave this as a conscious +-# choice for the user. This also increases chances charts run on environments with little +-# resources, such as Minikube. If you do want to specify resources, uncomment the following +-# lines, adjust them as necessary, and remove the curly braces after 'resources:'. +-# limits: +-# cpu: 100m +-# memory: 128Mi +-# requests: +-# cpu: 100m +-# memory: 128Mi + + networkPolicy: + # -- Specifies whether default network policies should be created. diff --git a/examples/giantswarm/patches/git/zot.patch b/examples/giantswarm/patches/git/zot.patch new file mode 100644 index 0000000..59969bb --- /dev/null +++ b/examples/giantswarm/patches/git/zot.patch @@ -0,0 +1,121 @@ +diff --git a/templates/deployment.yaml b/templates/deployment.yaml +index c48dda1..b6de3af 100644 +--- a/templates/deployment.yaml ++++ b/templates/deployment.yaml +@@ -24,12 +24,28 @@ spec: + {{- end }} + serviceAccountName: {{ include "zot.serviceAccountName" . }} + securityContext: +- {{- toYaml .Values.podSecurityContext | nindent 8 }} ++ fsGroup: 1337 ++ {{- if ge (int .Capabilities.KubeVersion.Minor) 19 }} ++ {{- with .Values.podSeccompProfile }} ++ seccompProfile: ++ {{- . | toYaml | nindent 10 }} ++ {{- end }} ++ {{- end }} + containers: + - name: {{ .Chart.Name }} + securityContext: +- {{- toYaml .Values.securityContext | nindent 12 }} +- image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" ++ {{- with .Values.containerSecurityContext }} ++ {{- . | toYaml | nindent 12 }} ++ {{- end }} ++ readOnlyRootFilesystem: true ++ runAsUser: 100 ++ {{- if ge (int .Capabilities.KubeVersion.Minor) 19 }} ++ {{- with .Values.seccompProfile }} ++ seccompProfile: ++ {{- . | toYaml | nindent 14 }} ++ {{- end }} ++ {{- end }} ++ image: "{{ .Values.image.registry }}/{{ .Values.image.image }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + {{- toYaml .Values.env | nindent 12 }} +diff --git a/templates/tests/test-connection-fails.yaml b/templates/tests/test-connection-fails.yaml +index 0e7a059..6ec4916 100644 +--- a/templates/tests/test-connection-fails.yaml ++++ b/templates/tests/test-connection-fails.yaml +@@ -8,8 +8,28 @@ metadata: + "helm.sh/hook": test + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed + spec: ++ securityContext: ++ fsGroup: 1337 ++ {{- if ge (int .Capabilities.KubeVersion.Minor) 19 }} ++ {{- with .Values.podSeccompProfile }} ++ seccompProfile: ++ {{- . | toYaml | nindent 10 }} ++ {{- end }} ++ {{- end }} + containers: + - name: wget ++ securityContext: ++ {{- with .Values.containerSecurityContext }} ++ {{- . | toYaml | nindent 12 }} ++ {{- end }} ++ readOnlyRootFilesystem: true ++ runAsUser: 100 ++ {{- if ge (int .Capabilities.KubeVersion.Minor) 19 }} ++ {{- with .Values.seccompProfile }} ++ seccompProfile: ++ {{- . | toYaml | nindent 14 }} ++ {{- end }} ++ {{- end }} + image: alpine:3.18 + command: + - sh +diff --git a/templates/tests/test-connection.yaml b/templates/tests/test-connection.yaml +index 59c64b4..2ded317 100644 +--- a/templates/tests/test-connection.yaml ++++ b/templates/tests/test-connection.yaml +@@ -8,8 +8,28 @@ metadata: + "helm.sh/hook": test + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed + spec: ++ securityContext: ++ fsGroup: 1337 ++ {{- if ge (int .Capabilities.KubeVersion.Minor) 19 }} ++ {{- with .Values.podSeccompProfile }} ++ seccompProfile: ++ {{- . | toYaml | nindent 10 }} ++ {{- end }} ++ {{- end }} + containers: + - name: wget ++ securityContext: ++ {{- with .Values.containerSecurityContext }} ++ {{- . | toYaml | nindent 12 }} ++ {{- end }} ++ readOnlyRootFilesystem: true ++ runAsUser: 100 ++ {{- if ge (int .Capabilities.KubeVersion.Minor) 19 }} ++ {{- with .Values.seccompProfile }} ++ seccompProfile: ++ {{- . | toYaml | nindent 14 }} ++ {{- end }} ++ {{- end }} + image: alpine:3.18 + command: + - sh +diff --git a/values.yaml b/values.yaml +index ac7f0f0..9730e9c 100644 +--- a/values.yaml ++++ b/values.yaml +@@ -3,10 +3,10 @@ + # Declare variables to be passed into your templates. + replicaCount: 1 + image: +- repository: ghcr.io/project-zot/zot-linux-amd64 +- pullPolicy: IfNotPresent +- # Overrides the image tag whose default is the chart appVersion. +- tag: "v2.0.0" ++ registry: gsoci.azurecr.io ++ image: dummy/zot-linux ++ pullPolicy: Always ++ tag: "" + serviceAccount: + # Specifies whether a service account should be created + create: true diff --git a/examples/giantswarm/patches/regexp/values-patches.yaml b/examples/giantswarm/patches/regexp/values-patches.yaml new file mode 100644 index 0000000..ffd14e4 --- /dev/null +++ b/examples/giantswarm/patches/regexp/values-patches.yaml @@ -0,0 +1,89 @@ +--- +name: Replace image repository in values +targets: + - values.yaml +before: |- + image: + repository: ghcr.io/project-zot/zot-linux-amd64 + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "v2.0.0" +after: |- + image: + repository: gsoci/dummy/zot-linux + pullPolicy: Always + tag: "" +--- +name: Fix security policies in the deployment +targets: + - templates/deployment.yaml +before: |- + \{\{- toYaml .Values.podSecurityContext .* +after: |- + fsGroup: 1337 + {{- if ge (int .Capabilities.KubeVersion.Minor) 19 }} + {{- with .Values.podSeccompProfile }} + seccompProfile: + {{- . | toYaml | nindent 10 }} + {{- end }} + {{- end }} +--- +name: Fix security policies in container +targets: + - templates/deployment.yaml +before: |- + \{\{- toYaml .Values.securityContext .* +after: |- + {{- with .Values.containerSecurityContext }} + {{- . | toYaml | nindent 12 }} + {{- end }} + readOnlyRootFilesystem: true + runAsUser: 100 + {{- if ge (int .Capabilities.KubeVersion.Minor) 19 }} + {{- with .Values.seccompProfile }} + seccompProfile: + {{- . | toYaml | nindent 14 }} + {{- end }} + {{- end }} +--- +name: Fix security policies in test jobs +targets: + - templates/tests/test-connection-fails.yaml + - templates/tests/test-connection.yaml +before: |- + spec: + containers: +after: |- + spec: + securityContext: + fsGroup: 1337 + {{- if ge (int .Capabilities.KubeVersion.Minor) 19 }} + {{- with .Values.podSeccompProfile }} + seccompProfile: + {{- . | toYaml | nindent 10 }} + {{- end }} + {{- end }} + containers: +--- +name: Fix security policies in test jobs containers +targets: + - templates/tests/test-connection-fails.yaml + - templates/tests/test-connection.yaml +before: |- + containers: + - name: wget +after: |- + containers: + - name: wget + securityContext: + {{- with .Values.containerSecurityContext }} + {{- . | toYaml | nindent 12 }} + {{- end }} + readOnlyRootFilesystem: true + runAsUser: 100 + {{- if ge (int .Capabilities.KubeVersion.Minor) 19 }} + {{- with .Values.seccompProfile }} + seccompProfile: + {{- . | toYaml | nindent 14 }} + {{- end }} + {{- end }}