diff --git a/README.md b/README.md index 9c0559f..b7b958b 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,117 @@ -Helm charts for Platform Engineering Workshop. +# Platform Engineering Workshop — Helm Charts +Helm charts that deploy a complete Platform Engineering workshop environment on OpenShift 4.x. Designed for use with the [platform-engineering-workshop](https://github.com/rhpds/platform-engineering-workshop) Ansible-based deployer, which bootstraps the cluster and deploys a single Argo CD `Application` CR pointing to the `app-of-apps/` chart. From there, Argo CD manages everything. -To verify the RHTAS installation & configuration: +> [!NOTE] +> This is a **workshop/demo environment**. Some design choices (storing passwords in Vault at deploy time, broad RBAC grants, shared credentials) reflect that priority. Don't use this as a production reference architecture. -1) Login to the OpenShift Cluster +## What gets deployed -2) Download `cosign` from the OCP console / "Command Line Tools" and install it in your PATH +The workshop stands up the following on a single OpenShift cluster: -3) `oc project trusted-artifact-signer` +| Component | Chart | Purpose | +|---|---|---| +| **HashiCorp Vault** | `vault/` | Secrets backend — stores tokens, passwords, and credentials | +| **External Secrets Operator** | `external-secrets/` | Syncs Vault secrets into Kubernetes `Secret` resources via `ExternalSecret` CRs | +| **OpenShift Pipelines** | `openshift-pipelines/` | Tekton-based CI/CD | +| **NooBaa** | `noobaa/` | S3-compatible object storage (backing store for Quay) | +| **GitLab** | `gitlab/` | Source code management — users, groups, and repos are created via init Jobs | +| **Keycloak** | `keycloak/` | SSO/OIDC provider for Developer Hub, Trusted Artifact Signer, and OpenShift login | +| **OpenShift OAuth** | `openshift-oauth/` | Adds Keycloak as an OpenID identity provider on the cluster OAuth CR | +| **Quay** | `quay/` | Container image registry | +| **RHDH GitOps** | `gitops/` | Dedicated Argo CD instance for Developer Hub-managed applications | +| **Red Hat Developer Hub** | `redhat-developer-hub/` | Internal developer portal (Backstage) | +| **Trusted Artifact Signer** | `rhtas/` | Sigstore-based container image signing (Fulcio, Rekor, etc.) | -4) Setup your environment +## Deployment settling time + +A full deployment can take around 30 minutes before all Argo CD Applications report as Synced and Healthy. The main bottleneck is GitLab — its own initialisation is slow, and our init Jobs (user/group/repo creation, PAT generation, Vault secret writes) can only run after GitLab is fully ready. Several downstream components then depend on secrets that GitLab's init writes to Vault: + +- **ExternalSecrets** like DevSpaces' `gitlab-oauth-config` won't sync until the corresponding Vault entry exists, which only happens after the GitLab init Job completes +- **Red Hat Developer Hub** depends on the GitLab PAT and webhook secret being in Vault before its own ExternalSecrets can resolve +- **Operators** (AMQ Streams, DevSpaces, OpenShift Pipelines) install via OLM Subscriptions, which can add a few minutes while CSVs install and operands start + +If an Application appears stuck, check whether its upstream dependency (usually GitLab or Vault) has finished initialising. + +## App-of-apps pattern + +The `app-of-apps/` chart is the root. It renders one Argo CD `Application` CR per component, each pointing back into this same repository at the appropriate chart path. Argo CD then syncs each child Application independently. + +Sync waves control ordering: + +- **Wave 0** — Foundational: Vault, External Secrets, OpenShift Pipelines, NooBaa +- **Wave 1** — Services: GitLab, Keycloak, Quay, RHDH GitOps +- **Wave 2** — Consumers: Red Hat Developer Hub, Trusted Artifact Signer + +Every child Application uses a foreground deletion finalizer, so deleting the root app-of-apps Application cascade-deletes everything. + +## Secret management + +Vault is the single source of truth for secrets. The flow works like this: + +1. **Ansible** provides known secrets (common password, Keycloak client secrets, ArgoCD password, etc.) as Helm values when creating the app-of-apps Application +2. **Vault's setup Job** (`vault/templates/cm-vault-setup.yaml`) initialises the KV v2 engine, configures Kubernetes auth, and **pre-populates** these known secrets at `kv/secrets//...` paths +3. **Service init Jobs** (GitLab, Quay) generate additional secrets at runtime (GitLab root PAT, webhook secret, Quay registry credentials) and write them to Vault +4. **ExternalSecret CRs** in the RHDH prereqs chart pull secrets from Vault into Kubernetes Secrets that Developer Hub consumes + +> [!IMPORTANT] +> The Vault setup Job pre-populates secrets using values passed through Helm. In a production setup you'd use a proper secret injection workflow. Here, the tradeoff is acceptable because the passwords are generated once by Ansible and the cluster is ephemeral. + +### Vault paths + +| Path | Written by | Consumed by | +|---|---|---| +| `kv/secrets/gitlab/root-password` | Vault setup Job | — | +| `kv/secrets/gitlab/token` | GitLab init Job | RHDH (ExternalSecret) | +| `kv/secrets/gitlab/webhook-secret` | GitLab init Job | — | +| `kv/secrets/keycloak/client-secret` | Vault setup Job | RHDH (ExternalSecret) | +| `kv/secrets/keycloak/openshift-client-secret` | Vault setup Job | OpenShift OAuth (ExternalSecret) | +| `kv/secrets/keycloak/plugin-client-secret` | Vault setup Job | — | +| `kv/secrets/quay/auth` | Quay config Job | — | +| `kv/secrets/quay/username` | Quay config Job | — | +| `kv/secrets/quay/password` | Quay config Job | — | +| `kv/secrets/rhdh/argocd-password` | Vault setup Job | RHDH (ExternalSecret) | +| `kv/secrets/rhdh/postgresql-password` | Vault setup Job | RHDH (ExternalSecret) | +| `kv/secrets/rhdh/kubernetes-sa-token` | RHDH SA token Job | RHDH (ExternalSecret) | +| `kv/secrets/gitlab/devspaces-oauth` | GitLab init Job | DevSpaces (ExternalSecret) | +| `kv/secrets/common/password` | Vault setup Job | — | + +## Developer authentication + +Workshop users (dev1, dev2, pe1, pe2) authenticate via Keycloak. The `openshift-oauth/` chart adds a **"developers"** OpenID Connect identity provider to the cluster OAuth CR alongside the default htpasswd provider. Users see both options on the OpenShift login page. + +DevSpaces reuses this flow — the DevSpaces operator hardcodes `provider="openshift"` in its gateway proxy config, so it always authenticates through OpenShift OAuth, which in turn redirects to Keycloak. + +## Embedded Ansible playbooks + +Several charts use a pattern where a `ConfigMap` contains an Ansible playbook, and a `Job` runs it using an Ansible execution environment image. This handles multi-step imperative setup that can't be expressed declaratively: + +- **`vault/templates/cm-vault-setup.yaml`** — Initialises Vault: retrieves the root token, creates policies, enables Kubernetes auth, enables the KV engine, and pre-populates secrets +- **`gitlab/templates/cm-gitlab-init.yaml`** — Waits for GitLab to be ready, creates a root PAT, configures application settings, creates users/groups/repos, imports repositories, and writes the PAT + webhook secret to Vault +- **`quay/quay-registry/templates/cm-config.yaml`** — Waits for the Quay registry to be ready, creates the admin user, extends the API token expiration, and writes registry credentials to Vault +- **`redhat-developer-hub/redhat-developer-hub-prereqs/templates/cm-sa-token-writer.yaml`** — Creates a `kubernetes.io/service-account-token` Secret, waits for the token to be populated, and writes it to Vault so RHDH can use it for cluster access +- **`redhat-developer-hub/redhat-developer-hub-config-template/templates/rhdh-config-template.yaml`** — Clones the Developer Hub config repo from GitLab, templates it with cluster-specific values, and pushes the result back + +These Jobs use the `quay.io/agnosticd/ee-multicloud` execution environment image (or `ose-cli` for simpler scripts) and follow Helm/Argo CD sync-wave ordering to ensure dependencies are ready. + +## Vault auto-unseal + +Vault uses Shamir key shares stored on the pod's PVC. A `CronJob` (`vault/templates/cronjob-auto-unseal.yaml`) runs every minute to check Vault's seal status and automatically unseal it if needed. This handles: + +- **Initial deployment** — initialises Vault, stores unseal keys, and unseals +- **Pod/cluster restarts** — detects the sealed state and unseals using the persisted keys + +## Verifying RHTAS + +To verify the Trusted Artifact Signer installation: + +1. Login to the OpenShift cluster + +2. Download `cosign` from the OCP console "Command Line Tools" and install it in your PATH + +3. `oc project trusted-artifact-signer` + +4. Setup your environment: ``` export TUF_URL=$(oc get tuf -o jsonpath='{.items[0].status.url}' -n trusted-artifact-signer) @@ -28,29 +130,27 @@ export SIGSTORE_REKOR_URL=$COSIGN_REKOR_URL export REKOR_REKOR_SERVER=$COSIGN_REKOR_URL ``` -5) `cosign initialize` +5. `cosign initialize` -6) Sign an arbitrary container image, for example +6. Sign an arbitrary container image: ``` echo "FROM scratch" > ./tmp.Dockerfile podman build . -f ./tmp.Dockerfile -t ttl.sh/rhtas/test-image:1h - podman push ttl.sh/rhtas/test-image:1h +cosign sign -y ttl.sh/rhtas/test-image:1h ``` -`cosign sign -y ttl.sh/rhtas/test-image:1h` - -When asked to authenticate, use one of the registered workshop users/password, e.g. `dev1@rhdemo.com` - - -7) Verify the signature +When asked to authenticate, use one of the registered workshop users, e.g. `dev1@rhdemo.com`. -`cosign verify --certificate-identity=dev1@rhdemo.com ttl.sh/rhtas/test-image:1h` +7. Verify the signature: -(add `| jq` to make it readable) - -8) Show signature/security info related to the OCI artifact +``` +cosign verify --certificate-identity=dev1@rhdemo.com ttl.sh/rhtas/test-image:1h | jq +``` -`cosign tree ttl.sh/rhtas/test-image:1h` +8. Show signature/security info related to the OCI artifact: +``` +cosign tree ttl.sh/rhtas/test-image:1h +``` \ No newline at end of file diff --git a/amq-streams/Chart.yaml b/amq-streams/Chart.yaml new file mode 100644 index 0000000..672752d --- /dev/null +++ b/amq-streams/Chart.yaml @@ -0,0 +1,19 @@ +apiVersion: v2 +name: amq-streams +description: A Helm chart for AMQ Streams (Kafka) with Streams Console +type: application +version: 0.1.0 + +dependencies: + - name: amq-streams-operator + version: 0.1.0 + repository: file://amq-streams-operator + - name: amq-streams-console-operator + version: 0.1.0 + repository: file://amq-streams-console-operator + - name: kafka-broker + version: 0.1.0 + repository: file://kafka-broker + - name: amq-streams-console + version: 0.1.0 + repository: file://amq-streams-console diff --git a/amq-streams/amq-streams-console-operator/Chart.yaml b/amq-streams/amq-streams-console-operator/Chart.yaml new file mode 100644 index 0000000..e5dc69f --- /dev/null +++ b/amq-streams/amq-streams-console-operator/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: amq-streams-console-operator +description: A Helm chart for Kubernetes +type: application +version: 0.1.0 diff --git a/amq-streams/amq-streams-console-operator/templates/_helpers.tpl b/amq-streams/amq-streams-console-operator/templates/_helpers.tpl new file mode 100644 index 0000000..063297f --- /dev/null +++ b/amq-streams/amq-streams-console-operator/templates/_helpers.tpl @@ -0,0 +1,77 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "amq-streams-console-operator.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 "amq-streams-console-operator.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 "amq-streams-console-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "amq-streams-console-operator.labels" -}} +helm.sh/chart: {{ include "amq-streams-console-operator.chart" . }} +{{ include "amq-streams-console-operator.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "amq-streams-console-operator.selectorLabels" -}} +app.kubernetes.io/name: {{ include "amq-streams-console-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Determine target namespace +*/}} +{{- define "amq-streams-console-operator.namespace" -}} +{{- if .Values.namespace }} +{{- printf "%s" .Values.namespace}} +{{- else }} +{{- printf "%s" .Release.Namespace }} +{{- end }} +{{- end }} + +{{/* +ArgoCD Syncwave +*/}} +{{- define "amq-streams-console-operator.argocd-syncwave" -}} +{{- if .Values.argocd }} +{{- if and (.Values.argocd.operator.syncwave) (.Values.argocd.enabled) -}} +argocd.argoproj.io/sync-wave: "{{ .Values.argocd.operator.syncwave }}" +{{- else }} +{{- "{}" }} +{{- end }} +{{- else }} +{{- "{}" }} +{{- end }} +{{- end }} diff --git a/amq-streams/amq-streams-console-operator/templates/amq-streams-console-subscription.yaml b/amq-streams/amq-streams-console-operator/templates/amq-streams-console-subscription.yaml new file mode 100644 index 0000000..8035bc1 --- /dev/null +++ b/amq-streams/amq-streams-console-operator/templates/amq-streams-console-subscription.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: {{ include "amq-streams-console-operator.name" . }}-operator + namespace: {{ include "amq-streams-console-operator.namespace" . }} + annotations: + {{- include "amq-streams-console-operator.argocd-syncwave" . | nindent 4 }} +spec: + channel: {{ .Values.subscription.channel }} + installPlanApproval: {{ .Values.subscription.installPlanApproval }} + name: {{ .Values.subscription.name }} + source: {{ .Values.subscription.source }} + sourceNamespace: {{ .Values.subscription.sourceNamespace }} diff --git a/amq-streams/amq-streams-console-operator/values.yaml b/amq-streams/amq-streams-console-operator/values.yaml new file mode 100644 index 0000000..05b84a0 --- /dev/null +++ b/amq-streams/amq-streams-console-operator/values.yaml @@ -0,0 +1,16 @@ +nameOverride: "amq-streams-console" +fullnameOverride: "" + +namespace: openshift-operators + +subscription: + channel: amq-streams-2.9.x + installPlanApproval: Automatic + name: amq-streams-console + source: redhat-operators + sourceNamespace: openshift-marketplace + +argocd: + enabled: true + operator: + syncwave: "-2" diff --git a/amq-streams/amq-streams-console/Chart.yaml b/amq-streams/amq-streams-console/Chart.yaml new file mode 100644 index 0000000..17f6d8d --- /dev/null +++ b/amq-streams/amq-streams-console/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: amq-streams-console +description: A Helm chart for Kubernetes +type: application +version: 0.1.0 diff --git a/amq-streams/amq-streams-console/templates/_helpers.tpl b/amq-streams/amq-streams-console/templates/_helpers.tpl new file mode 100644 index 0000000..5800722 --- /dev/null +++ b/amq-streams/amq-streams-console/templates/_helpers.tpl @@ -0,0 +1,64 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "amq-streams-console.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "amq-streams-console.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 "amq-streams-console.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "amq-streams-console.labels" -}} +helm.sh/chart: {{ include "amq-streams-console.chart" . }} +{{ include "amq-streams-console.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "amq-streams-console.selectorLabels" -}} +app.kubernetes.io/name: {{ include "amq-streams-console.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +ArgoCD Syncwave +*/}} +{{- define "amq-streams-console.argocd-syncwave" -}} +{{- if and (.Values.argocd) (.Values.argocd.syncwave) }} +{{- if (.Values.argocd.syncwave.enabled) -}} +argocd.argoproj.io/sync-wave: "{{ .Values.argocd.syncwave.console }}" +{{- else }} +{{- "{}" }} +{{- end }} +{{- else }} +{{- "{}" }} +{{- end }} +{{- end }} diff --git a/amq-streams/amq-streams-console/templates/console-cr.yaml b/amq-streams/amq-streams-console/templates/console-cr.yaml new file mode 100644 index 0000000..0bdc815 --- /dev/null +++ b/amq-streams/amq-streams-console/templates/console-cr.yaml @@ -0,0 +1,28 @@ +apiVersion: console.streamshub.github.com/v1alpha1 +kind: Console +metadata: + name: {{ include "amq-streams-console.name" . }} + {{- if .Values.namespace }} + namespace: {{ .Values.namespace }} + {{- end }} + labels: + {{- include "amq-streams-console.labels" . | nindent 4 }} + annotations: + {{- include "amq-streams-console.argocd-syncwave" . | nindent 4 }} + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + hostname: {{ include "amq-streams-console.name" . }}.{{ .Values.subdomain }} + metricsSources: + - name: ocp-prometheus + type: openshift-monitoring + kafkaClusters: + - name: {{ .Values.kafka.name }} + namespace: {{ .Values.namespace }} + listener: plain + metricsSource: ocp-prometheus + properties: + values: [] + valuesFrom: [] + credentials: + kafkaUser: + name: {{ include "amq-streams-console.name" . }}-kafka-user diff --git a/amq-streams/amq-streams-console/templates/console-kafka-user.yaml b/amq-streams/amq-streams-console/templates/console-kafka-user.yaml new file mode 100644 index 0000000..cf1005c --- /dev/null +++ b/amq-streams/amq-streams-console/templates/console-kafka-user.yaml @@ -0,0 +1,44 @@ +{{- if eq .Values.kafka.authentication.saslMechanism "SCRAM-SHA-512" -}} +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaUser +metadata: + name: {{ include "amq-streams-console.name" . }}-kafka-user + {{- if .Values.namespace }} + namespace: {{ .Values.namespace }} + {{- end }} + labels: + {{- include "amq-streams-console.labels" . | nindent 4 }} + strimzi.io/cluster: {{ .Values.kafka.name }} + annotations: + {{- include "amq-streams-console.argocd-syncwave" . | nindent 4 }} + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + authentication: + type: scram-sha-512 + {{- if eq .Values.kafka.authorization "simple" }} + authorization: + type: simple + acls: + - operations: + - Describe + - DescribeConfigs + resource: + type: cluster + - operations: + - Read + - Describe + - DescribeConfigs + resource: + name: '*' + patternType: literal + type: topic + - operations: + - Read + - Describe + resource: + name: '*' + patternType: literal + type: group + {{- end }} +{{- end }} diff --git a/amq-streams/amq-streams-console/values.yaml b/amq-streams/amq-streams-console/values.yaml new file mode 100644 index 0000000..b2fbe1b --- /dev/null +++ b/amq-streams/amq-streams-console/values.yaml @@ -0,0 +1,15 @@ +nameOverride: streams-console + +namespace: +subdomain: + +kafka: + name: kafka + authentication: + saslMechanism: SCRAM-SHA-512 + authorization: simple + +argocd: + syncwave: + enabled: true + console: "1" diff --git a/amq-streams/amq-streams-operator/Chart.yaml b/amq-streams/amq-streams-operator/Chart.yaml new file mode 100644 index 0000000..083db3f --- /dev/null +++ b/amq-streams/amq-streams-operator/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: amq-streams-operator +description: A Helm chart for Kubernetes +type: application +version: 0.1.0 diff --git a/amq-streams/amq-streams-operator/templates/_helpers.tpl b/amq-streams/amq-streams-operator/templates/_helpers.tpl new file mode 100644 index 0000000..a6645fb --- /dev/null +++ b/amq-streams/amq-streams-operator/templates/_helpers.tpl @@ -0,0 +1,77 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "amq-streams-operator.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 "amq-streams-operator.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 "amq-streams-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "amq-streams-operator.labels" -}} +helm.sh/chart: {{ include "amq-streams-operator.chart" . }} +{{ include "amq-streams-operator.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "amq-streams-operator.selectorLabels" -}} +app.kubernetes.io/name: {{ include "amq-streams-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Determine target namespace +*/}} +{{- define "amq-streams-operator.namespace" -}} +{{- if .Values.namespace }} +{{- printf "%s" .Values.namespace}} +{{- else }} +{{- printf "%s" .Release.Namespace }} +{{- end }} +{{- end }} + +{{/* +ArgoCD Syncwave +*/}} +{{- define "amq-streams-operator.argocd-syncwave" -}} +{{- if .Values.argocd }} +{{- if and (.Values.argocd.operator.syncwave) (.Values.argocd.enabled) -}} +argocd.argoproj.io/sync-wave: "{{ .Values.argocd.operator.syncwave }}" +{{- else }} +{{- "{}" }} +{{- end }} +{{- else }} +{{- "{}" }} +{{- end }} +{{- end }} diff --git a/amq-streams/amq-streams-operator/templates/amq-streams-subscription.yaml b/amq-streams/amq-streams-operator/templates/amq-streams-subscription.yaml new file mode 100644 index 0000000..1c71b4b --- /dev/null +++ b/amq-streams/amq-streams-operator/templates/amq-streams-subscription.yaml @@ -0,0 +1,18 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: {{ include "amq-streams-operator.name" . }}-operator + namespace: {{ include "amq-streams-operator.namespace" . }} + annotations: + {{- include "amq-streams-operator.argocd-syncwave" . | nindent 4 }} +spec: + channel: {{ .Values.subscription.channel }} + installPlanApproval: {{ .Values.subscription.installPlanApproval }} + name: {{ .Values.subscription.name }} + source: {{ .Values.subscription.source }} + sourceNamespace: {{ .Values.subscription.sourceNamespace }} + config: + env: + - name: STRIMZI_OPERATION_TIMEOUT_MS + value: "{{ .Values.subscription.operationTimeoutMs }}" diff --git a/amq-streams/amq-streams-operator/values.yaml b/amq-streams/amq-streams-operator/values.yaml new file mode 100644 index 0000000..7e8c769 --- /dev/null +++ b/amq-streams/amq-streams-operator/values.yaml @@ -0,0 +1,17 @@ +nameOverride: "amq-streams" +fullnameOverride: "" + +namespace: openshift-operators + +subscription: + channel: stable + installPlanApproval: Automatic + name: amq-streams + source: redhat-operators + sourceNamespace: openshift-marketplace + operationTimeoutMs: "600000" + +argocd: + enabled: true + operator: + syncwave: "-2" diff --git a/amq-streams/kafka-broker/Chart.yaml b/amq-streams/kafka-broker/Chart.yaml new file mode 100644 index 0000000..854e021 --- /dev/null +++ b/amq-streams/kafka-broker/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: kafka-broker +description: A Helm chart for AMQ Streams broker +type: application +version: 0.1.0 diff --git a/amq-streams/kafka-broker/templates/_helpers.tpl b/amq-streams/kafka-broker/templates/_helpers.tpl new file mode 100644 index 0000000..0f3a25a --- /dev/null +++ b/amq-streams/kafka-broker/templates/_helpers.tpl @@ -0,0 +1,91 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "kafka-broker.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "kafka-broker.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 "kafka-broker.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "kafka-broker.labels" -}} +helm.sh/chart: {{ include "kafka-broker.chart" . }} +{{ include "kafka-broker.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "kafka-broker.selectorLabels" -}} +app.kubernetes.io/name: {{ include "kafka-broker.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Kafka authentication +*/}} +{{- define "kafka-broker.authentication" -}} +{{- if eq .Values.authentication.saslMechanism "SCRAM-SHA-512" -}} +authentication: + type: scram-sha-512 +{{- else }} +authentication: {} +{{- end }} +{{- end }} + +{{/* +ArgoCD Syncwave for Kafka resources +*/}} +{{- define "kafka-broker.argocd-syncwave" -}} +{{- if and (.Values.argocd) (.Values.argocd.syncwave) }} +{{- if (.Values.argocd.syncwave.enabled) -}} +argocd.argoproj.io/sync-wave: "{{ .Values.argocd.syncwave.kafka }}" +{{- else }} +{{- "{}" }} +{{- end }} +{{- else }} +{{- "{}" }} +{{- end }} +{{- end }} + +{{/* +ArgoCD Syncwave for Namespace +*/}} +{{- define "kafka-namespace.argocd-syncwave" -}} +{{- if and (.Values.argocd) (.Values.argocd.syncwave) }} +{{- if (.Values.argocd.syncwave.enabled) -}} +argocd.argoproj.io/sync-wave: "{{ .Values.argocd.syncwave.namespace }}" +{{- else }} +{{- "{}" }} +{{- end }} +{{- else }} +{{- "{}" }} +{{- end }} +{{- end }} diff --git a/amq-streams/kafka-broker/templates/kafka-cr.yaml b/amq-streams/kafka-broker/templates/kafka-cr.yaml new file mode 100644 index 0000000..7117f45 --- /dev/null +++ b/amq-streams/kafka-broker/templates/kafka-cr.yaml @@ -0,0 +1,45 @@ +{{- if .Values.kafka.enabled -}} +apiVersion: kafka.strimzi.io/v1beta2 +kind: Kafka +metadata: + name: {{ include "kafka-broker.name" . }} + {{- if .Values.namespace }} + namespace: {{ .Values.namespace }} + {{- end }} + labels: + {{- include "kafka-broker.labels" . | nindent 4 }} + annotations: + strimzi.io/node-pools: enabled + strimzi.io/kraft: enabled + {{- include "kafka-broker.argocd-syncwave" . | nindent 4 }} + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + kafka: + version: {{ .Values.kafka.version }} + metadataVersion: {{ .Values.kafka.metadataVersion }} + {{- if eq .Values.authorization "simple" }} + authorization: + type: simple + {{- end }} + listeners: + - name: plain + port: 9092 + type: internal + tls: false + {{- include "kafka-broker.authentication" . | nindent 6 }} + config: + allow.everyone.if.no.acl.found: 'true' + auto.create.topics.enable: {{ .Values.kafka.config.autoCreateTopics }} + offsets.topic.replication.factor: {{ .Values.kafka.config.offsetsTopicReplicationFactor }} + transaction.state.log.min.isr: {{ .Values.kafka.config.transactionStateLogMinIsr }} + transaction.state.log.replication.factor: {{ .Values.kafka.config.transactionStateLogReplicationFactor }} + default.replication.factor: {{ .Values.kafka.config.defaultReplicationFactor }} + min.insync.replicas: {{ .Values.kafka.config.minInsyncReplicas }} + entityOperator: + topicOperator: + resources: + {{- toYaml .Values.kafka.entityOperator.topicOperator.resources | nindent 8 }} + userOperator: + resources: + {{- toYaml .Values.kafka.entityOperator.userOperator.resources | nindent 8 }} +{{- end }} diff --git a/amq-streams/kafka-broker/templates/kafka-namespace.yaml b/amq-streams/kafka-broker/templates/kafka-namespace.yaml new file mode 100644 index 0000000..0266c24 --- /dev/null +++ b/amq-streams/kafka-broker/templates/kafka-namespace.yaml @@ -0,0 +1,10 @@ +{{- if .Values.namespace }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.namespace }} + annotations: + {{- include "kafka-namespace.argocd-syncwave" . | nindent 4 }} + labels: + argocd.argoproj.io/managed-by: openshift-gitops +{{- end }} diff --git a/amq-streams/kafka-broker/templates/kafka-nodepool-broker-controller.yaml b/amq-streams/kafka-broker/templates/kafka-nodepool-broker-controller.yaml new file mode 100644 index 0000000..6c9fdf0 --- /dev/null +++ b/amq-streams/kafka-broker/templates/kafka-nodepool-broker-controller.yaml @@ -0,0 +1,26 @@ +{{- if not .Values.kafka.controller.enabled -}} +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaNodePool +metadata: + name: {{ include "kafka-broker.name" . }}-broker + {{- if .Values.namespace }} + namespace: {{ .Values.namespace }} + {{- end }} + labels: + strimzi.io/cluster: {{ include "kafka-broker.name" . }} + annotations: + {{- include "kafka-broker.argocd-syncwave" . | nindent 4 }} + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + replicas: {{ .Values.kafka.broker.replicas }} + roles: + - broker + - controller + resources: + {{- toYaml .Values.kafka.resources | nindent 4 }} + storage: + type: jbod + volumes: + - id: 0 + type: ephemeral +{{ end }} diff --git a/amq-streams/kafka-broker/templates/kafka-topic.yaml b/amq-streams/kafka-broker/templates/kafka-topic.yaml new file mode 100644 index 0000000..f0db723 --- /dev/null +++ b/amq-streams/kafka-broker/templates/kafka-topic.yaml @@ -0,0 +1,23 @@ +{{- range .Values.topics }} +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + name: {{ .name | replace "_" "-" }} + {{- if $.Values.namespace }} + namespace: {{ $.Values.namespace }} + {{- end }} + labels: + strimzi.io/cluster: {{ include "kafka-broker.name" $ }} + {{- include "kafka-broker.labels" $ | nindent 4 }} + annotations: + {{- include "kafka-broker.argocd-syncwave" $ | nindent 4 }} + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + partitions: {{ .partitions }} + replicas: {{ $.Values.kafka.config.defaultReplicationFactor }} + config: + retention.ms: {{ .retention }} + segment.bytes: 1073741824 + topicName: {{ .name }} +{{- end }} diff --git a/amq-streams/kafka-broker/templates/kafka-user-cr.yaml b/amq-streams/kafka-broker/templates/kafka-user-cr.yaml new file mode 100644 index 0000000..4b4ebcc --- /dev/null +++ b/amq-streams/kafka-broker/templates/kafka-user-cr.yaml @@ -0,0 +1,54 @@ +{{- if eq .Values.authentication.saslMechanism "SCRAM-SHA-512" -}} +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaUser +metadata: + name: {{ .Values.authentication.clientId }} + {{- if .Values.namespace }} + namespace: {{ .Values.namespace }} + {{- end }} + labels: + {{- include "kafka-broker.labels" . | nindent 4 }} + strimzi.io/cluster: {{ include "kafka-broker.name" . }} + annotations: + {{- include "kafka-broker.argocd-syncwave" . | nindent 4 }} + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + authentication: + type: scram-sha-512 + password: + valueFrom: + secretKeyRef: + name: {{ include "kafka-broker.name" . }}-user-secret + key: clientSecret + {{- if eq .Values.authorization "simple" }} + authorization: + type: simple + acls: + - operations: + - Describe + resource: + type: cluster + - operations: + - Create + - Describe + - Read + - Write + resource: + name: '*' + patternType: literal + type: topic + - operations: + - Read + resource: + name: '*' + patternType: literal + type: group + - operations: + - Read + - Describe + resource: + name: '*' + patternType: literal + type: transactionalId + {{- end }} +{{- end }} diff --git a/amq-streams/kafka-broker/templates/kafka-user-secret.yaml b/amq-streams/kafka-broker/templates/kafka-user-secret.yaml new file mode 100644 index 0000000..9e1cc1c --- /dev/null +++ b/amq-streams/kafka-broker/templates/kafka-user-secret.yaml @@ -0,0 +1,26 @@ +{{- if eq .Values.authentication.saslMechanism "SCRAM-SHA-512" -}} +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ include "kafka-broker.name" . }}-user-secret + {{- if .Values.namespace }} + namespace: {{ .Values.namespace }} + {{- end }} + labels: + {{- include "kafka-broker.labels" . | nindent 4 }} + annotations: + {{- include "kafka-broker.argocd-syncwave" . | nindent 4 }} +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-secret-store + kind: ClusterSecretStore + target: + name: {{ include "kafka-broker.name" . }}-user-secret + creationPolicy: Owner + data: + - secretKey: clientSecret + remoteRef: + key: secrets/kafka/user-password + property: value +{{- end }} diff --git a/amq-streams/kafka-broker/values.yaml b/amq-streams/kafka-broker/values.yaml new file mode 100644 index 0000000..ae8ef17 --- /dev/null +++ b/amq-streams/kafka-broker/values.yaml @@ -0,0 +1,60 @@ +nameOverride: "kafka" + +kafka: + enabled: true + version: 4.1.0 + metadataVersion: 4.1-IV1 + broker: + replicas: 1 + controller: + enabled: false + config: + autoCreateTopics: false + defaultReplicationFactor: 1 + offsetsTopicReplicationFactor: 1 + transactionStateLogReplicationFactor: 1 + transactionStateLogMinIsr: 1 + minInsyncReplicas: 1 + entityOperator: + topicOperator: + resources: + limits: + cpu: 500m + memory: 512M + requests: + cpu: 250m + memory: 256M + userOperator: + resources: + limits: + cpu: 500m + memory: 512M + requests: + cpu: 250m + memory: 256M + resources: + limits: + cpu: '1' + memory: 2G + requests: + cpu: 300m + memory: 500M + +namespace: + +authentication: + clientId: franz + saslMechanism: SCRAM-SHA-512 + +authorization: simple + +topics: + - name: intake + partitions: 1 + retention: -1 + +argocd: + syncwave: + enabled: true + kafka: "0" + namespace: "-1" diff --git a/amq-streams/values.yaml b/amq-streams/values.yaml new file mode 100644 index 0000000..6a20f07 --- /dev/null +++ b/amq-streams/values.yaml @@ -0,0 +1,8 @@ +kafka-broker: + namespace: kafka + authentication: + clientId: parasol + +amq-streams-console: + namespace: kafka + subdomain: "" diff --git a/app-of-apps/Chart.yaml b/app-of-apps/Chart.yaml new file mode 100644 index 0000000..8742b8f --- /dev/null +++ b/app-of-apps/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: app-of-apps +description: Root app-of-apps chart that deploys all platform components as Argo CD Applications +type: application +version: 0.1.0 diff --git a/app-of-apps/templates/_helpers.tpl b/app-of-apps/templates/_helpers.tpl new file mode 100644 index 0000000..28e635e --- /dev/null +++ b/app-of-apps/templates/_helpers.tpl @@ -0,0 +1,36 @@ +{{/* +Common sync policy for child Applications. +Provides automated sync with prune, selfHeal, retry with backoff, and standard syncOptions. +*/}} +{{- define "app-of-apps.syncPolicy" -}} +syncPolicy: + automated: + prune: true + selfHeal: true + retry: + backoff: + duration: 5s + factor: 2 + maxDuration: 2m0s + limit: 30 + syncOptions: + - CreateNamespace=true + - RespectIgnoreDifferences=true + - SkipDryRunOnMissingResource=true +{{- end }} + +{{/* +Common Application metadata with foreground finalizer. +Usage: {{ include "app-of-apps.metadata" (dict "name" "my-app" "namespace" .Values.argocd.namespace "syncWave" "0") }} +*/}} +{{- define "app-of-apps.metadata" -}} +metadata: + name: {{ .name }} + namespace: {{ .namespace }} + labels: + app.kubernetes.io/part-of: app-of-apps + annotations: + argocd.argoproj.io/sync-wave: "{{ .syncWave }}" + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +{{- end }} diff --git a/app-of-apps/templates/amq-streams.yaml b/app-of-apps/templates/amq-streams.yaml new file mode 100644 index 0000000..2ff2654 --- /dev/null +++ b/app-of-apps/templates/amq-streams.yaml @@ -0,0 +1,22 @@ +{{- if .Values.amqStreams.enabled }} +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.amqStreams.name "namespace" .Values.argocd.namespace "syncWave" "0") }} +spec: + destination: + namespace: {{ .Values.amqStreams.namespace }} + server: https://kubernetes.default.svc + project: default + source: + path: amq-streams + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + kafka-broker: + namespace: {{ .Values.amqStreams.namespace }} + amq-streams-console: + namespace: {{ .Values.amqStreams.namespace }} + subdomain: {{ .Values.cluster.subdomain }} +{{ include "app-of-apps.syncPolicy" . | indent 2 }} +{{- end }} diff --git a/app-of-apps/templates/developer-hub.yaml b/app-of-apps/templates/developer-hub.yaml new file mode 100644 index 0000000..53e1ad1 --- /dev/null +++ b/app-of-apps/templates/developer-hub.yaml @@ -0,0 +1,42 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" (printf "%s-prereqs" .Values.developerHub.name) "namespace" .Values.argocd.namespace "syncWave" "2") }} +spec: + destination: + namespace: {{ .Values.developerHub.namespace }} + server: https://kubernetes.default.svc + project: default + source: + path: developer-hub/developer-hub-prereqs + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + vault: + namespace: {{ .Values.vault.namespace }} + name: {{ .Values.vault.name }} +{{ include "app-of-apps.syncPolicy" . | indent 2 }} +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" (printf "%s-application" .Values.developerHub.name) "namespace" .Values.argocd.namespace "syncWave" "3") }} +spec: + destination: + namespace: {{ .Values.developerHub.namespace }} + server: https://kubernetes.default.svc + project: default + source: + repoURL: https://{{ .Values.developerHub.application.git.host }}/{{ .Values.developerHub.application.git.group }}/{{ .Values.developerHub.application.git.repo }}.git + targetRevision: {{ .Values.developerHub.application.git.revision }} + path: . + helm: + valuesObject: + backstage: + host: {{ .Values.developerHub.config.backstage.host }} + gitlab: + host: {{ .Values.developerHub.config.gitlab.host }} + argocd: + host: {{ .Values.developerHub.config.argocd.host }} + kubernetes: + apiUrl: {{ .Values.developerHub.config.kubernetes.apiUrl }} +{{ include "app-of-apps.syncPolicy" . | indent 2 }} diff --git a/app-of-apps/templates/devspaces.yaml b/app-of-apps/templates/devspaces.yaml new file mode 100644 index 0000000..9838fef --- /dev/null +++ b/app-of-apps/templates/devspaces.yaml @@ -0,0 +1,20 @@ +{{- if .Values.devspaces.enabled }} +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.devspaces.name "namespace" .Values.argocd.namespace "syncWave" "0") }} +spec: + destination: + namespace: {{ .Values.devspaces.namespace }} + server: https://kubernetes.default.svc + project: default + source: + path: devspaces + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + devspaces-instance: + gitlab: + host: {{ .Values.gitlab.host }} +{{ include "app-of-apps.syncPolicy" . | indent 2 }} +{{- end }} diff --git a/app-of-apps/templates/external-secrets.yaml b/app-of-apps/templates/external-secrets.yaml new file mode 100644 index 0000000..74b3f86 --- /dev/null +++ b/app-of-apps/templates/external-secrets.yaml @@ -0,0 +1,29 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.externalSecrets.name "namespace" .Values.argocd.namespace "syncWave" "0") }} +spec: + destination: + namespace: {{ .Values.externalSecrets.namespace }} + server: https://kubernetes.default.svc + project: default + ignoreDifferences: + - group: admissionregistration.k8s.io + kind: MutatingWebhookConfiguration + jqPathExpressions: + - '.webhooks[]?.clientConfig.caBundle' + source: + path: external-secrets + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + vault-integration: + vault: + namespace: {{ .Values.vault.namespace }} + name: {{ .Values.vault.name }} + auth: + namespace: {{ .Values.vault.authNamespace }} + syncPolicy: + automated: {} + syncOptions: + - CreateNamespace=true diff --git a/app-of-apps/templates/gitlab.yaml b/app-of-apps/templates/gitlab.yaml new file mode 100644 index 0000000..8c6267a --- /dev/null +++ b/app-of-apps/templates/gitlab.yaml @@ -0,0 +1,37 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.gitlab.name "namespace" .Values.argocd.namespace "syncWave" "1") }} +spec: + destination: + namespace: {{ .Values.gitlab.namespace }} + server: https://kubernetes.default.svc + project: default + source: + path: gitlab + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + parameters: + - name: gitlab.smtp.host + value: {{ .Values.gitlab.smtp.host | quote }} + - name: gitlab.ssh.host + value: {{ .Values.gitlab.ssh.host | quote }} + - name: gitlab.rootPassword + value: {{ .Values.gitlab.rootPassword | quote }} + - name: gitlab.users.password + value: {{ .Values.gitlab.usersPassword | quote }} + - name: gitlab.host + value: {{ .Values.gitlab.host }} + - name: cluster.subdomain + value: {{ .Values.gitlab.cluster.subdomain }} + - name: gitops.namespace + value: {{ .Values.gitlab.gitops.namespace }} + - name: quay.host + value: {{ .Values.gitlab.quay.host }} + - name: vault.name + value: {{ .Values.vault.name }} + - name: vault.namespace + value: {{ .Values.vault.namespace }} + - name: orchestrator.namespace + value: {{ .Values.orchestrator.namespace }} +{{ include "app-of-apps.syncPolicy" . | indent 2 }} diff --git a/app-of-apps/templates/keycloak.yaml b/app-of-apps/templates/keycloak.yaml new file mode 100644 index 0000000..687eec5 --- /dev/null +++ b/app-of-apps/templates/keycloak.yaml @@ -0,0 +1,46 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.keycloak.name "namespace" .Values.argocd.namespace "syncWave" "1") }} +spec: + destination: + namespace: {{ .Values.keycloak.namespace }} + server: https://kubernetes.default.svc + project: default + ignoreDifferences: + - group: k8s.keycloak.org + kind: KeycloakRealmImport + jqPathExpressions: + - .. | (.id, .containerId, .secret)? | strings + source: + path: keycloak + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + keycloak: + nameOverride: {{ .Values.keycloak.crName }} + route: + host: {{ .Values.keycloak.route.host }} + ingress: + enabled: {{ .Values.keycloak.externalAccess }} + keycloak-realm-import: + keycloak: + name: {{ .Values.keycloak.crName }} + realm: + name: {{ .Values.keycloak.realm.name }} + client: + backstage: + name: {{ .Values.keycloak.client.backstage.name }} + redirectUri: {{ .Values.keycloak.client.backstage.redirectUri }} + webOrigin: {{ .Values.keycloak.client.backstage.webOrigin }} + secret: {{ .Values.keycloak.client.backstage.secret | quote }} + backstagePlugin: + name: {{ .Values.keycloak.client.backstagePlugin.name }} + secret: {{ .Values.keycloak.client.backstagePlugin.secret | quote }} + openshift: + name: {{ .Values.keycloak.client.openshift.name }} + redirectUri: {{ .Values.keycloak.client.openshift.redirectUri }} + secret: {{ .Values.keycloak.client.openshift.secret | quote }} + users: + password: {{ .Values.keycloak.users.password | quote }} +{{ include "app-of-apps.syncPolicy" . | indent 2 }} diff --git a/app-of-apps/templates/noobaa.yaml b/app-of-apps/templates/noobaa.yaml new file mode 100644 index 0000000..5b6708a --- /dev/null +++ b/app-of-apps/templates/noobaa.yaml @@ -0,0 +1,27 @@ +{{- if .Values.noobaa.enabled }} +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.noobaa.name "namespace" .Values.argocd.namespace "syncWave" "0") }} +spec: + destination: + namespace: {{ .Values.noobaa.namespace }} + server: https://kubernetes.default.svc + project: default + ignoreDifferences: + - group: noobaa.io + kind: NooBaa + jsonPointers: + - /metadata/labels + - /spec/coreResources + - /spec/dbResources + - /spec/endpoints + source: + path: noobaa + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + noobaa: + nameOverride: {{ .Values.noobaa.name }} +{{ include "app-of-apps.syncPolicy" . | indent 2 }} +{{- end }} diff --git a/app-of-apps/templates/openshift-oauth.yaml b/app-of-apps/templates/openshift-oauth.yaml new file mode 100644 index 0000000..b529656 --- /dev/null +++ b/app-of-apps/templates/openshift-oauth.yaml @@ -0,0 +1,20 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.openshiftOAuth.name "namespace" .Values.argocd.namespace "syncWave" "3") }} +spec: + destination: + namespace: {{ .Values.openshiftOAuth.namespace }} + server: https://kubernetes.default.svc + project: default + source: + path: openshift-oauth + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + keycloak: + host: {{ .Values.keycloak.route.host }} + realm: {{ .Values.keycloak.realm.name }} + oidc: + clientId: {{ .Values.keycloak.client.openshift.name }} +{{ include "app-of-apps.syncPolicy" . | indent 2 }} diff --git a/app-of-apps/templates/openshift-pipelines.yaml b/app-of-apps/templates/openshift-pipelines.yaml new file mode 100644 index 0000000..296fec0 --- /dev/null +++ b/app-of-apps/templates/openshift-pipelines.yaml @@ -0,0 +1,23 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.openshiftPipelines.name "namespace" .Values.argocd.namespace "syncWave" "0") }} +spec: + destination: + namespace: {{ .Values.openshiftPipelines.namespace }} + server: https://kubernetes.default.svc + project: default + source: + path: openshift-pipelines + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + syncPolicy: + automated: {} + retry: + backoff: + duration: 5s + factor: 2 + maxDuration: 3m0s + limit: 2 + syncOptions: + - CreateNamespace=false + - RespectIgnoreDifferences=true diff --git a/app-of-apps/templates/orchestrator.yaml b/app-of-apps/templates/orchestrator.yaml new file mode 100644 index 0000000..fa0c83c --- /dev/null +++ b/app-of-apps/templates/orchestrator.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.orchestrator.name "namespace" .Values.argocd.namespace "syncWave" "3") }} +spec: + destination: + namespace: {{ .Values.orchestrator.namespace }} + server: https://kubernetes.default.svc + project: default + source: + path: orchestrator + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + orchestrator: + backstage: + namespace: {{ .Values.orchestrator.namespace }} + backend: + url: {{ .Values.orchestrator.backstage.backend.url }} + openshift: + url: {{ .Values.orchestrator.openshift.url }} + gitlab: + url: {{ .Values.orchestrator.gitlab.url }} +{{ include "app-of-apps.syncPolicy" . | indent 2 }} diff --git a/app-of-apps/templates/parasol.yaml b/app-of-apps/templates/parasol.yaml new file mode 100644 index 0000000..c57b532 --- /dev/null +++ b/app-of-apps/templates/parasol.yaml @@ -0,0 +1,55 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.parasol.name "namespace" .Values.argocd.namespace "syncWave" "2") }} +spec: + destination: + namespace: {{ .Values.parasol.namespace }} + server: https://kubernetes.default.svc + project: default + source: + path: parasol + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + keycloak-realm-import: + keycloak: + namespace: {{ .Values.keycloak.namespace }} + parasol: + gitlab: + rootPassword: {{ .Values.gitlab.rootPassword | quote }} + host: {{ .Values.gitlab.host }} + registry: + host: {{ .Values.quay.host }} + username: {{ .Values.quay.adminUser }} + password: {{ .Values.quay.adminUserPassword | quote }} + parasol: + web: + sso: + dev: + host: {{ .Values.keycloak.route.host }} + staging: + host: {{ .Values.keycloak.route.host }} + prod: + host: {{ .Values.keycloak.route.host }} + cluster: + subdomain: {{ .Values.cluster.subdomain }} + parasol-build: + gitlab: + rootPassword: {{ .Values.gitlab.rootPassword | quote }} + host: {{ .Values.gitlab.host }} + registry: + host: {{ .Values.quay.host }} + username: {{ .Values.quay.adminUser }} + password: {{ .Values.quay.adminUserPassword | quote }} + cluster: + subdomain: {{ .Values.cluster.subdomain }} + parasol-templates: + gitlab: + rootPassword: {{ .Values.gitlab.rootPassword | quote }} + host: {{ .Values.gitlab.host }} + gitops: + namespace: {{ .Values.rhdhGitops.namespace }} + cluster: + subdomain: {{ .Values.cluster.subdomain }} +{{ include "app-of-apps.syncPolicy" . | indent 2 }} diff --git a/app-of-apps/templates/quay.yaml b/app-of-apps/templates/quay.yaml new file mode 100644 index 0000000..fe446d1 --- /dev/null +++ b/app-of-apps/templates/quay.yaml @@ -0,0 +1,28 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.quay.name "namespace" .Values.argocd.namespace "syncWave" "1") }} +spec: + destination: + namespace: {{ .Values.quay.namespace }} + server: https://kubernetes.default.svc + project: default + source: + path: quay + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + quay-registry: + quay: + host: {{ .Values.quay.host }} + adminUser: {{ .Values.quay.adminUser }} + adminUserPassword: {{ .Values.quay.adminUserPassword | quote }} + organizations: {{ .Values.quay.organizations | toJson }} + users: {{ .Values.quay.users | toJson }} + vault: + name: {{ .Values.vault.name }} + namespace: {{ .Values.vault.namespace }} + noobaa: + name: {{ .Values.noobaa.name }} + namespace: {{ .Values.noobaa.namespace }} +{{ include "app-of-apps.syncPolicy" . | indent 2 }} diff --git a/app-of-apps/templates/redhat-developer-hub.yaml b/app-of-apps/templates/redhat-developer-hub.yaml new file mode 100644 index 0000000..8c48285 --- /dev/null +++ b/app-of-apps/templates/redhat-developer-hub.yaml @@ -0,0 +1,61 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.rhdh.name "namespace" .Values.argocd.namespace "syncWave" "2") }} +spec: + destination: + namespace: {{ .Values.rhdh.namespace }} + server: https://kubernetes.default.svc + project: default + source: + path: redhat-developer-hub + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + redhat-developer-hub-prereqs: + vault: + namespace: {{ .Values.vault.namespace }} + name: {{ .Values.vault.name }} + backstage: + postgresql: + password: {{ .Values.vault.secrets.rhdh.postgresqlPassword | quote }} + redhat-developer-hub-config-template: + gitlab: + rootPassword: {{ .Values.rhdh.configTemplate.gitlab.rootPassword | quote }} + host: {{ .Values.rhdh.configTemplate.gitlab.host }} + backstage: + host: {{ .Values.rhdh.configTemplate.backstage.host }} + keycloak: + host: {{ .Values.rhdh.configTemplate.keycloak.host }} + realm: {{ .Values.rhdh.configTemplate.keycloak.realm }} + loginRealm: {{ .Values.rhdh.configTemplate.keycloak.loginRealm }} + clientId: {{ .Values.rhdh.configTemplate.keycloak.clientId }} + clientSecret: {{ .Values.rhdh.configTemplate.keycloak.clientSecret | quote }} + gitops: + host: {{ .Values.rhdh.configTemplate.gitops.host }} + kubernetes: + api: {{ .Values.rhdh.configTemplate.kubernetes.api }} + cluster: + subdomain: {{ .Values.rhdh.configTemplate.cluster.subdomain }} + redhat-developer-hub-application: + gitops: + namespace: {{ .Values.rhdh.application.gitops.namespace }} + helm: + version: {{ .Values.rhdh.application.helm.version }} + values: + git: + host: {{ .Values.rhdh.application.helm.values.git.host }} + syncPolicy: + automated: + prune: true + selfHeal: true + retry: + backoff: + duration: 10s + factor: 2 + maxDuration: 10m + limit: 15 + syncOptions: + - CreateNamespace=true + - RespectIgnoreDifferences=true + - ApplyOutOfSyncOnly=true diff --git a/app-of-apps/templates/rhdh-gitops.yaml b/app-of-apps/templates/rhdh-gitops.yaml new file mode 100644 index 0000000..5cb9bfe --- /dev/null +++ b/app-of-apps/templates/rhdh-gitops.yaml @@ -0,0 +1,17 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.rhdhGitops.name "namespace" .Values.argocd.namespace "syncWave" "1") }} +spec: + destination: + namespace: {{ .Values.rhdhGitops.namespace }} + server: https://kubernetes.default.svc + project: default + source: + path: gitops + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + nameOverride: {{ .Values.rhdhGitops.name }} + password: {{ .Values.rhdhGitops.password | quote }} +{{ include "app-of-apps.syncPolicy" . | indent 2 }} diff --git a/app-of-apps/templates/rhtas.yaml b/app-of-apps/templates/rhtas.yaml new file mode 100644 index 0000000..ac0cada --- /dev/null +++ b/app-of-apps/templates/rhtas.yaml @@ -0,0 +1,21 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.rhtas.name "namespace" .Values.argocd.namespace "syncWave" "2") }} +spec: + destination: + namespace: {{ .Values.rhtas.namespace }} + server: https://kubernetes.default.svc + project: default + source: + path: rhtas + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + trusted-artifact-signer: + oidc: {{ .Values.rhtas.oidcIssuer }} + email: {{ .Values.rhtas.rootCert.email }} + org: {{ .Values.rhtas.rootCert.org }} + instance: {{ .Values.rhtas.instance }} + namespace: {{ .Values.rhtas.namespace }} +{{ include "app-of-apps.syncPolicy" . | indent 2 }} diff --git a/app-of-apps/templates/vault.yaml b/app-of-apps/templates/vault.yaml new file mode 100644 index 0000000..25d714a --- /dev/null +++ b/app-of-apps/templates/vault.yaml @@ -0,0 +1,49 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +{{ include "app-of-apps.metadata" (dict "name" .Values.vault.name "namespace" .Values.argocd.namespace "syncWave" "0") }} +spec: + destination: + namespace: {{ .Values.vault.namespace }} + server: https://kubernetes.default.svc + project: default + ignoreDifferences: + - group: admissionregistration.k8s.io + kind: MutatingWebhookConfiguration + jqPathExpressions: + - '.webhooks[]?.clientConfig.caBundle' + source: + path: vault + repoURL: {{ .Values.gitops.repoURL }} + targetRevision: {{ .Values.gitops.targetRevision }} + helm: + valuesObject: + nameOverride: {{ .Values.vault.name }} + kubernetes: + apiserver: {{ .Values.cluster.apiServer }} + vault: + auth: + namespace: {{ .Values.vault.authNamespace }} + secrets: + gitlab: + rootPassword: {{ .Values.vault.secrets.gitlab.rootPassword | quote }} + keycloak: + clientId: {{ .Values.vault.secrets.keycloak.clientId }} + clientSecret: {{ .Values.vault.secrets.keycloak.clientSecret | quote }} + pluginClientSecret: {{ .Values.vault.secrets.keycloak.pluginClientSecret | quote }} + openshiftClientSecret: {{ .Values.vault.secrets.keycloak.openshiftClientSecret | quote }} + rhdh: + argocdPassword: {{ .Values.vault.secrets.rhdh.argocdPassword | quote }} + postgresqlPassword: {{ .Values.vault.secrets.rhdh.postgresqlPassword | quote }} + orchestrator: + token: {{ .Values.vault.secrets.orchestrator.token | quote }} + common: + password: {{ .Values.vault.secrets.common.password | quote }} + litellm: + apiUrl: {{ .Values.vault.secrets.litellm.apiUrl | quote }} + apiKey: {{ .Values.vault.secrets.litellm.apiKey | quote }} + kafka: + userPassword: {{ .Values.vault.secrets.kafka.userPassword | quote }} + syncPolicy: + automated: {} + syncOptions: + - CreateNamespace=true diff --git a/app-of-apps/values.yaml b/app-of-apps/values.yaml new file mode 100644 index 0000000..c89c7ad --- /dev/null +++ b/app-of-apps/values.yaml @@ -0,0 +1,195 @@ +gitops: + repoURL: https://github.com/evanshortiss/etx-app-platform-helm.git + targetRevision: main + +argocd: + namespace: openshift-gitops + +cluster: + subdomain: "" + apiServer: "" + +common: + password: "" + +vault: + name: vault + namespace: vault + authNamespace: default + secrets: + gitlab: + rootPassword: "" + keycloak: + clientId: backstage + clientSecret: "" + pluginClientSecret: "" + openshiftClientSecret: "" + rhdh: + argocdPassword: "" + postgresqlPassword: password + orchestrator: + token: "" + common: + password: "" + litellm: + apiUrl: "" + apiKey: "" + kafka: + userPassword: "" + +externalSecrets: + name: external-secrets + namespace: external-secrets + +openshiftPipelines: + name: openshift-pipelines + namespace: openshift-operators + +noobaa: + enabled: true + name: noobaa + namespace: openshift-storage + +gitlab: + name: gitlab + namespace: gitlab + host: "" + smtp: + host: "" + ssh: + host: "" + rootPassword: "" + usersPassword: "" + cluster: + subdomain: "" + gitops: + namespace: "" + quay: + host: "" + +keycloak: + name: keycloak + namespace: keycloak + crName: keycloak + externalAccess: false + route: + host: "" + realm: + name: backstage + client: + backstage: + name: backstage + redirectUri: "" + webOrigin: "" + secret: "" + backstagePlugin: + name: backstage-plugin + secret: "" + openshift: + name: openshift + redirectUri: "" + secret: "" + users: + password: "" + +quay: + name: quay + namespace: quay-registry + host: "" + adminUser: quayadmin + adminUserPassword: "" + organizations: + - parasol + users: [] + +developerHub: + name: developer-hub + namespace: rhdh + config: + backstage: + host: "" + gitlab: + host: "" + argocd: + host: "" + kubernetes: + apiUrl: "" + application: + git: + host: "github.com" + group: redhat-ads-tech + repo: ocp-app-platform-demo-developer-hub-config + revision: main + +rhdhGitops: + name: rhdh-gitops + namespace: rhdh-gitops + password: "" + +rhdh: + name: backstage-bootstrap + namespace: backstage + configTemplate: + gitlab: + rootPassword: "" + host: "" + backstage: + host: "" + keycloak: + host: "" + realm: backstage + loginRealm: backstage + clientId: backstage-plugin + clientSecret: "" + gitops: + host: "" + kubernetes: + api: "" + cluster: + subdomain: "" + application: + gitops: + namespace: openshift-gitops + helm: + version: 1.8.2 + values: + git: + host: "" + +rhtas: + name: trusted-artifact-signer + namespace: trusted-artifact-signer + instance: securesign + oidcIssuer: "" + rootCert: + email: admin@rhdemo.com + org: Parasol + +openshiftOAuth: + name: openshift-oauth + namespace: openshift-config + +devspaces: + enabled: true + name: devspaces + namespace: openshift-devspaces + +amqStreams: + enabled: true + name: amq-streams + namespace: kafka + +parasol: + name: parasol + namespace: parasol-dev + +orchestrator: + name: orchestrator + namespace: backstage + backstage: + backend: + url: "" + openshift: + url: "" + gitlab: + url: "" diff --git a/developer-hub/Chart.yaml b/developer-hub/Chart.yaml new file mode 100644 index 0000000..fd86ce9 --- /dev/null +++ b/developer-hub/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: developer-hub +description: Deploys Red Hat Developer Hub via the RHDH Operator +type: application +version: 0.1.0 diff --git a/developer-hub/developer-hub-prereqs/Chart.yaml b/developer-hub/developer-hub-prereqs/Chart.yaml new file mode 100644 index 0000000..7ca39f3 --- /dev/null +++ b/developer-hub/developer-hub-prereqs/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: developer-hub-prereqs +description: Prerequisites for Developer Hub via the RHDH Operator +type: application +version: 0.1.0 diff --git a/developer-hub/developer-hub-prereqs/templates/_helpers.tpl b/developer-hub/developer-hub-prereqs/templates/_helpers.tpl new file mode 100644 index 0000000..072d815 --- /dev/null +++ b/developer-hub/developer-hub-prereqs/templates/_helpers.tpl @@ -0,0 +1,64 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "developer-hub-prereqs.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "developer-hub-prereqs.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 "developer-hub-prereqs.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "developer-hub-prereqs.labels" -}} +helm.sh/chart: {{ include "developer-hub-prereqs.chart" . }} +{{ include "developer-hub-prereqs.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "developer-hub-prereqs.selectorLabels" -}} +app.kubernetes.io/name: {{ include "developer-hub-prereqs.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +ArgoCD Syncwave +*/}} +{{- define "developer-hub-prereqs.argocd-syncwave" -}} +{{- if .Values.argocd }} +{{- if and (.Values.argocd.syncwave) (.Values.argocd.enabled) -}} +argocd.argoproj.io/sync-wave: "{{ .Values.argocd.syncwave }}" +{{- else }} +{{- "{}" }} +{{- end }} +{{- else }} +{{- "{}" }} +{{- end }} +{{- end }} diff --git a/developer-hub/developer-hub-prereqs/templates/cluster-role-binding-default-sa-admin.yaml b/developer-hub/developer-hub-prereqs/templates/cluster-role-binding-default-sa-admin.yaml new file mode 100644 index 0000000..10d2235 --- /dev/null +++ b/developer-hub/developer-hub-prereqs/templates/cluster-role-binding-default-sa-admin.yaml @@ -0,0 +1,14 @@ +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: cluster-admin-default-{{ .Release.Namespace }} + annotations: + {{- include "developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} +subjects: + - kind: ServiceAccount + namespace: {{ .Release.Namespace }} + name: default +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin diff --git a/developer-hub/developer-hub-prereqs/templates/cm-sa-token-writer.yaml b/developer-hub/developer-hub-prereqs/templates/cm-sa-token-writer.yaml new file mode 100644 index 0000000..d55fafa --- /dev/null +++ b/developer-hub/developer-hub-prereqs/templates/cm-sa-token-writer.yaml @@ -0,0 +1,83 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: sa-token-writer + labels: + {{- include "developer-hub-prereqs.labels" . | nindent 4 }} + annotations: + argocd.argoproj.io/sync-wave: "1" +data: + playbook.yaml: | + --- + - name: Write SA token to Vault + hosts: localhost + vars: + namespace: {{ .Release.Namespace }} + vault_namespace: {{ .Values.vault.namespace }} + vault_name: {{ .Values.vault.name }} + tasks: + - name: Create service account token secret + kubernetes.core.k8s: + state: present + definition: + apiVersion: v1 + kind: Secret + type: kubernetes.io/service-account-token + metadata: + name: default-token + namespace: '{{ "{{" }} namespace {{ "}}" }}' + annotations: + kubernetes.io/service-account.name: default + + - name: Wait for token to be populated + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + name: default-token + namespace: '{{ "{{" }} namespace {{ "}}" }}' + register: r_token_secret + retries: 60 + delay: 5 + until: + - r_token_secret.resources is defined + - r_token_secret.resources | length > 0 + - r_token_secret.resources[0].data is defined + - r_token_secret.resources[0].data.token is defined + - r_token_secret.resources[0].data.token | length > 0 + + - name: Decode token + ansible.builtin.set_fact: + sa_token: '{{ "{{" }} r_token_secret.resources[0].data.token | b64decode {{ "}}" }}' + + - name: Retrieve Vault Pod + kubernetes.core.k8s_info: + kind: Pod + name: '{{ "{{" }} vault_name {{ "}}" }}-0' + namespace: '{{ "{{" }} vault_namespace {{ "}}" }}' + register: r_vault + retries: 120 + delay: 5 + until: + - r_vault.resources is defined + - r_vault.resources | length > 0 + - r_vault.resources[0].status is defined + - r_vault.resources[0].status.phase is defined + - r_vault.resources[0].status.phase == 'Running' + + - name: Read Vault token + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + name: vault-token + namespace: '{{ "{{" }} vault_namespace {{ "}}" }}' + register: r_vault_token + + - name: Set Vault token + ansible.builtin.set_fact: + vault_token: '{{ "{{" }} r_vault_token.resources[0].data.token | b64decode {{ "}}" }}' + + - name: Write SA token to Vault + kubernetes.core.k8s_exec: + namespace: '{{ "{{" }} vault_namespace {{ "}}" }}' + pod: '{{ "{{" }} vault_name {{ "}}" }}-0' + command: 'sh -c "VAULT_TOKEN={{ "{{" }} vault_token {{ "}}" }} vault kv put kv/secrets/rhdh/kubernetes-sa-token value={{ "{{" }} sa_token {{ "}}" }}"' diff --git a/developer-hub/developer-hub-prereqs/templates/job-sa-token.yaml b/developer-hub/developer-hub-prereqs/templates/job-sa-token.yaml new file mode 100644 index 0000000..ddea2c0 --- /dev/null +++ b/developer-hub/developer-hub-prereqs/templates/job-sa-token.yaml @@ -0,0 +1,29 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: sa-token-writer + labels: + {{- include "developer-hub-prereqs.labels" . | nindent 4 }} + annotations: + argocd.argoproj.io/sync-wave: "1" + argocd.argoproj.io/hook: Sync + argocd.argoproj.io/hook-delete-policy: BeforeHookCreation +spec: + backoffLimit: 10 + template: + spec: + serviceAccountName: default + restartPolicy: OnFailure + containers: + - name: sa-token-writer + image: quay.io/agnosticd/ee-multicloud:latest + command: + - ansible-playbook + - /playbook/playbook.yaml + volumeMounts: + - name: playbook + mountPath: /playbook + volumes: + - name: playbook + configMap: + name: sa-token-writer diff --git a/developer-hub/developer-hub-prereqs/templates/namespace.yaml b/developer-hub/developer-hub-prereqs/templates/namespace.yaml new file mode 100644 index 0000000..b822529 --- /dev/null +++ b/developer-hub/developer-hub-prereqs/templates/namespace.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.namespace }} + labels: + {{- include "developer-hub-prereqs.labels" . | nindent 4 }} + annotations: + argocd.argoproj.io/sync-wave: "-2" diff --git a/developer-hub/developer-hub-prereqs/templates/operator-group.yaml b/developer-hub/developer-hub-prereqs/templates/operator-group.yaml new file mode 100644 index 0000000..829b227 --- /dev/null +++ b/developer-hub/developer-hub-prereqs/templates/operator-group.yaml @@ -0,0 +1,11 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: rhdh-operator + namespace: {{ .Values.namespace }} + labels: + {{- include "developer-hub-prereqs.labels" . | nindent 4 }} + annotations: + argocd.argoproj.io/sync-wave: "-2" +spec: + upgradeStrategy: Default diff --git a/developer-hub/developer-hub-prereqs/templates/subscription.yaml b/developer-hub/developer-hub-prereqs/templates/subscription.yaml new file mode 100644 index 0000000..0c2ee7c --- /dev/null +++ b/developer-hub/developer-hub-prereqs/templates/subscription.yaml @@ -0,0 +1,15 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: rhdh + namespace: {{ .Values.namespace }} + labels: + {{- include "developer-hub-prereqs.labels" . | nindent 4 }} + annotations: + argocd.argoproj.io/sync-wave: "-2" +spec: + channel: {{ .Values.operator.channel }} + installPlanApproval: Automatic + name: rhdh + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/developer-hub/developer-hub-prereqs/values.yaml b/developer-hub/developer-hub-prereqs/values.yaml new file mode 100644 index 0000000..bec4247 --- /dev/null +++ b/developer-hub/developer-hub-prereqs/values.yaml @@ -0,0 +1,14 @@ +nameOverride: "developer-hub-prereqs" + +namespace: rhdh + +vault: + namespace: vault + name: vault + +operator: + channel: fast-1.8 + +argocd: + enabled: true + syncwave: "-1" diff --git a/developer-hub/values.yaml b/developer-hub/values.yaml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/developer-hub/values.yaml @@ -0,0 +1 @@ + diff --git a/devspaces/Chart.yaml b/devspaces/Chart.yaml new file mode 100644 index 0000000..27e053b --- /dev/null +++ b/devspaces/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v2 +name: devspaces +description: A Helm chart for OpenShift Dev Spaces +type: application +version: 0.1.0 + +dependencies: + - name: devspaces-operator + version: 0.1.0 + repository: file://devspaces-operator + - name: devspaces-instance + version: 0.1.0 + repository: file://devspaces-instance diff --git a/devspaces/devspaces-instance/Chart.yaml b/devspaces/devspaces-instance/Chart.yaml new file mode 100644 index 0000000..36aa6cc --- /dev/null +++ b/devspaces/devspaces-instance/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: devspaces-instance +description: A Helm chart for the OpenShift Dev Spaces CheCluster instance +type: application +version: 0.1.0 diff --git a/devspaces/devspaces-instance/templates/_helpers.tpl b/devspaces/devspaces-instance/templates/_helpers.tpl new file mode 100644 index 0000000..35076af --- /dev/null +++ b/devspaces/devspaces-instance/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "devspaces-instance.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Determine target namespace +*/}} +{{- define "devspaces-instance.namespace" -}} +{{- if .Values.namespace }} +{{- printf "%s" .Values.namespace }} +{{- else }} +{{- printf "%s" .Release.Namespace }} +{{- end }} +{{- end }} + +{{/* +ArgoCD Syncwave for CheCluster instance +*/}} +{{- define "devspaces-instance.argocd-syncwave" -}} +{{- if .Values.argocd }} +{{- if and (.Values.argocd.instance.syncwave) (.Values.argocd.enabled) -}} +argocd.argoproj.io/sync-wave: "{{ .Values.argocd.instance.syncwave }}" +{{- else }} +{{- "{}" }} +{{- end }} +{{- else }} +{{- "{}" }} +{{- end }} +{{- end }} diff --git a/devspaces/devspaces-instance/templates/checluster.yaml b/devspaces/devspaces-instance/templates/checluster.yaml new file mode 100644 index 0000000..ce4b327 --- /dev/null +++ b/devspaces/devspaces-instance/templates/checluster.yaml @@ -0,0 +1,64 @@ +--- +apiVersion: org.eclipse.che/v2 +kind: CheCluster +metadata: + name: {{ include "devspaces-instance.name" . }} + namespace: {{ include "devspaces-instance.namespace" . }} + annotations: + {{- include "devspaces-instance.argocd-syncwave" . | nindent 4 }} +spec: + components: + cheServer: + extraProperties: + CHE_OIDC_USERNAME__CLAIM: email + debug: false + logLevel: INFO + dashboard: {} + devWorkspace: {} + devfileRegistry: {} + imagePuller: + enable: false + metrics: + enable: true + pluginRegistry: + openVSXURL: 'https://open-vsx.org' + containerRegistry: {} + devEnvironments: + startTimeoutSeconds: {{ .Values.devEnvironments.startTimeoutSeconds }} + secondsOfRunBeforeIdling: {{ .Values.devEnvironments.secondsOfRunBeforeIdling }} + maxNumberOfWorkspacesPerUser: {{ .Values.devEnvironments.maxNumberOfWorkspacesPerUser }} + defaultContainerResources: + limits: + cpu: {{ .Values.devEnvironments.resources.limits.cpu | quote }} + memory: {{ .Values.devEnvironments.resources.limits.memory | quote }} + requests: + cpu: {{ .Values.devEnvironments.resources.requests.cpu | quote }} + memory: {{ .Values.devEnvironments.resources.requests.memory | quote }} + containerResourceCaps: + limits: + cpu: {{ .Values.devEnvironments.resources.limits.cpu | quote }} + memory: {{ .Values.devEnvironments.resources.limits.memory | quote }} + containerBuildConfiguration: + openShiftSecurityContextConstraint: container-build + disableContainerBuildCapabilities: false + defaultEditor: {{ .Values.devEnvironments.defaultEditor }} + defaultNamespace: + autoProvision: true + template: -devspaces + secondsOfInactivityBeforeIdling: 1800 + storage: + pvcStrategy: per-user + gitServices: + gitlab: + - secretName: gitlab-oauth-config + endpoint: https://{{ .Values.gitlab.host }} + # DevSpaces authenticates via OpenShift OAuth — the operator's gateway proxy + # hardcodes provider="openshift" and ignores external OIDC overrides. Workshop + # users log in through the "developers" OpenID provider added to the cluster + # OAuth CR (see openshift-oauth/ chart), which redirects to Keycloak. + networking: + auth: + gateway: + configLabels: + app: che + component: che-gateway-config diff --git a/devspaces/devspaces-instance/templates/es-continue-llm.yaml b/devspaces/devspaces-instance/templates/es-continue-llm.yaml new file mode 100644 index 0000000..3e327e4 --- /dev/null +++ b/devspaces/devspaces-instance/templates/es-continue-llm.yaml @@ -0,0 +1,34 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: continue-llm-credentials + namespace: {{ include "devspaces-instance.namespace" . }} + annotations: + {{- include "devspaces-instance.argocd-syncwave" . | nindent 4 }} +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-secret-store + kind: ClusterSecretStore + target: + name: continue-llm-credentials + creationPolicy: Owner + template: + metadata: + labels: + app.kubernetes.io/part-of: che.eclipse.org + app.kubernetes.io/component: workspaces-config + annotations: + controller.devfile.io/mount-as: env + data: + LLM_API_KEY: "{{ printf "{{ .api_key }}" }}" + LLM_BASE_URL: "{{ printf "{{ .base_url }}" }}" + data: + - secretKey: api_key + remoteRef: + key: secrets/litellm/credentials + property: api_key + - secretKey: base_url + remoteRef: + key: secrets/litellm/credentials + property: base_url diff --git a/devspaces/devspaces-instance/templates/es-gitlab-oauth.yaml b/devspaces/devspaces-instance/templates/es-gitlab-oauth.yaml new file mode 100644 index 0000000..14201e9 --- /dev/null +++ b/devspaces/devspaces-instance/templates/es-gitlab-oauth.yaml @@ -0,0 +1,35 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: gitlab-oauth-config + namespace: {{ include "devspaces-instance.namespace" . }} + annotations: + {{- include "devspaces-instance.argocd-syncwave" . | nindent 4 }} +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-secret-store + kind: ClusterSecretStore + target: + name: gitlab-oauth-config + creationPolicy: Owner + template: + metadata: + labels: + app.kubernetes.io/part-of: che.eclipse.org + app.kubernetes.io/component: oauth-scm-configuration + annotations: + che.eclipse.org/oauth-scm-server: gitlab + che.eclipse.org/scm-server-endpoint: https://{{ .Values.gitlab.host }} + data: + id: {{ printf "{{ .id }}" | quote }} + secret: {{ printf "{{ .secret }}" | quote }} + data: + - secretKey: id + remoteRef: + key: secrets/gitlab/devspaces-oauth + property: id + - secretKey: secret + remoteRef: + key: secrets/gitlab/devspaces-oauth + property: secret diff --git a/devspaces/devspaces-instance/values.yaml b/devspaces/devspaces-instance/values.yaml new file mode 100644 index 0000000..cd76c56 --- /dev/null +++ b/devspaces/devspaces-instance/values.yaml @@ -0,0 +1,25 @@ +nameOverride: "devspaces" +fullnameOverride: "" + +namespace: "" + +devEnvironments: + startTimeoutSeconds: 300 + secondsOfRunBeforeIdling: 600 + maxNumberOfWorkspacesPerUser: 2 + defaultEditor: che-incubator/che-code/latest + resources: + limits: + memory: 2Gi + cpu: "2" + requests: + memory: 512Mi + cpu: 250m + +gitlab: + host: "" + +argocd: + enabled: true + instance: + syncwave: "0" diff --git a/devspaces/devspaces-operator/Chart.yaml b/devspaces/devspaces-operator/Chart.yaml new file mode 100644 index 0000000..e343c7e --- /dev/null +++ b/devspaces/devspaces-operator/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: devspaces-operator +description: A Helm chart for the OpenShift Dev Spaces operator +type: application +version: 0.1.0 diff --git a/devspaces/devspaces-operator/templates/_helpers.tpl b/devspaces/devspaces-operator/templates/_helpers.tpl new file mode 100644 index 0000000..e8c91c3 --- /dev/null +++ b/devspaces/devspaces-operator/templates/_helpers.tpl @@ -0,0 +1,92 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "devspaces-operator.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 "devspaces-operator.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 "devspaces-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "devspaces-operator.labels" -}} +helm.sh/chart: {{ include "devspaces-operator.chart" . }} +{{ include "devspaces-operator.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "devspaces-operator.selectorLabels" -}} +app.kubernetes.io/name: {{ include "devspaces-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Determine target namespace +*/}} +{{- define "devspaces-operator.namespace" -}} +{{- if .Values.namespace }} +{{- printf "%s" .Values.namespace }} +{{- else }} +{{- printf "%s" .Release.Namespace }} +{{- end }} +{{- end }} + +{{/* +ArgoCD Syncwave for operator subscription +*/}} +{{- define "devspaces-operator.argocd-syncwave" -}} +{{- if .Values.argocd }} +{{- if and (.Values.argocd.operator.syncwave) (.Values.argocd.enabled) -}} +argocd.argoproj.io/sync-wave: "{{ .Values.argocd.operator.syncwave }}" +{{- else }} +{{- "{}" }} +{{- end }} +{{- else }} +{{- "{}" }} +{{- end }} +{{- end }} + +{{/* +ArgoCD Syncwave for operatorgroup +*/}} +{{- define "devspaces-operatorgroup.argocd-syncwave" -}} +{{- if .Values.argocd }} +{{- if and (.Values.argocd.operatorgroup.syncwave) (.Values.argocd.enabled) -}} +argocd.argoproj.io/sync-wave: "{{ .Values.argocd.operatorgroup.syncwave }}" +{{- else }} +{{- "{}" }} +{{- end }} +{{- else }} +{{- "{}" }} +{{- end }} +{{- end }} diff --git a/devspaces/devspaces-operator/templates/devspaces-operatorgroup.yaml b/devspaces/devspaces-operator/templates/devspaces-operatorgroup.yaml new file mode 100644 index 0000000..8bc0e1b --- /dev/null +++ b/devspaces/devspaces-operator/templates/devspaces-operatorgroup.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: "{{ include "devspaces-operator.name" . }}-operatorgroup" + namespace: {{ include "devspaces-operator.namespace" . }} + annotations: + {{- include "devspaces-operatorgroup.argocd-syncwave" . | nindent 4 }} +spec: {} diff --git a/devspaces/devspaces-operator/templates/devspaces-subscription.yaml b/devspaces/devspaces-operator/templates/devspaces-subscription.yaml new file mode 100644 index 0000000..6f979e9 --- /dev/null +++ b/devspaces/devspaces-operator/templates/devspaces-subscription.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: {{ include "devspaces-operator.name" . }}-operator + namespace: {{ include "devspaces-operator.namespace" . }} + annotations: + {{- include "devspaces-operator.argocd-syncwave" . | nindent 4 }} +spec: + channel: {{ .Values.devspaces.subscription.channel }} + installPlanApproval: {{ .Values.devspaces.subscription.installPlanApproval }} + name: {{ .Values.devspaces.subscription.name }} + source: {{ .Values.devspaces.subscription.source }} + sourceNamespace: {{ .Values.devspaces.subscription.sourceNamespace }} + startingCSV: {{ .Values.devspaces.subscription.startingCSV }} diff --git a/devspaces/devspaces-operator/values.yaml b/devspaces/devspaces-operator/values.yaml new file mode 100644 index 0000000..ee64f79 --- /dev/null +++ b/devspaces/devspaces-operator/values.yaml @@ -0,0 +1,20 @@ +nameOverride: "devspaces" +fullnameOverride: "" + +namespace: "" + +devspaces: + subscription: + channel: stable + installPlanApproval: Automatic + name: devspaces + source: redhat-operators + startingCSV: devspacesoperator.v3.26.0 + sourceNamespace: openshift-marketplace + +argocd: + enabled: true + operatorgroup: + syncwave: "-3" + operator: + syncwave: "-2" diff --git a/devspaces/values.yaml b/devspaces/values.yaml new file mode 100644 index 0000000..e69de29 diff --git a/gitlab/templates/cm-gitlab-init.yaml b/gitlab/templates/cm-gitlab-init.yaml index da9e282..5b29fdf 100644 --- a/gitlab/templates/cm-gitlab-init.yaml +++ b/gitlab/templates/cm-gitlab-init.yaml @@ -14,11 +14,25 @@ data: root_password: {{ $.Values.gitlab.rootPassword }} user_create: true tasks: - - name: Pause for 5 minutes waiting for GitLab - ansible.builtin.pause: - minutes: 5 + - name: Wait for GitLab pod to be ready + kubernetes.core.k8s_info: + kind: Pod + namespace: '{{ "{{" }} gitlab_namespace {{ "}}" }}' + label_selectors: + - app=gitlab + register: r_gitlab_pod + retries: 120 + delay: 10 + until: + - r_gitlab_pod.resources is defined + - r_gitlab_pod.resources | length > 0 + - r_gitlab_pod.resources[0].status is defined + - r_gitlab_pod.resources[0].status.phase is defined + - r_gitlab_pod.resources[0].status.phase == 'Running' + - r_gitlab_pod.resources[0].status.containerStatuses is defined + - r_gitlab_pod.resources[0].status.containerStatuses | selectattr('ready', 'equalto', true) | list | length == r_gitlab_pod.resources[0].status.containerStatuses | length - - name: Check GitLab Liveness + - name: Wait for GitLab API to be available ansible.builtin.uri: url: https://{{ $.Values.gitlab.host }}/api/v4/projects method: GET @@ -66,10 +80,14 @@ data: PRIVATE-TOKEN: '{{ "{{" }} root_token {{ "}}" }}' validate_certs: false status_code: 200 + retries: 10 + delay: 5 + register: r_application_settings + until: r_application_settings.status == 200 {{- range $item := .Values.gitlab.users.users }} - - name: Create users + - name: Create user {{ $item.id }} ansible.builtin.uri: url: https://{{ $.Values.gitlab.host }}/api/v4/users method: POST @@ -85,11 +103,13 @@ data: headers: PRIVATE-TOKEN: '{{ "{{" }} root_token {{ "}}" }}' validate_certs: false - status_code: 201 + status_code: + - 201 + - 409 register: r_user - retries: 100 + retries: 10 delay: 5 - until: r_user.status == 201 + until: r_user.status in [201, 409] {{- end }} - name: List users @@ -104,7 +124,7 @@ data: {{- range $item := .Values.gitlab.groups }} - - name: Create group + - name: Create group {{ $item.name }} ansible.builtin.uri: url: https://{{ $.Values.gitlab.host }}/api/v4/groups method: POST @@ -116,11 +136,27 @@ data: headers: PRIVATE-TOKEN: '{{ "{{" }} root_token {{ "}}" }}' validate_certs: false - status_code: 201 - register: r_group - retries: 100 + status_code: + - 201 + - 400 + - 409 + register: r_group_create + retries: 10 delay: 5 - until: r_group.status == 201 + until: r_group_create.status in [201, 400, 409] + failed_when: + - r_group_create.status == 400 + - "'has already been taken' not in (r_group_create.json | default({}) | string)" + + - name: Look up group {{ $item.name }} + ansible.builtin.uri: + url: https://{{ $.Values.gitlab.host }}/api/v4/groups/{{ $item.name }} + method: GET + headers: + PRIVATE-TOKEN: '{{ "{{" }} root_token {{ "}}" }}' + validate_certs: false + status_code: 200 + register: r_group {{- if $item.repo }} @@ -140,23 +176,52 @@ data: headers: PRIVATE-TOKEN: '{{ "{{" }} root_token {{ "}}" }}' validate_certs: false - status_code: 201 - retries: 100 + status_code: + - 201 + - 400 + - 409 + retries: 10 delay: 5 register: r_import - until: r_import.status == 201 + until: r_import.status in [201, 400, 409] + failed_when: + - r_import.status == 400 + - "'has already been taken' not in (r_import.json | default({}) | string)" loop: {{- range $item1 := $item.repo }} - name: {{ $item1.name }} url: {{ $item1.url }} checkPipeline: {{ include "gitlab.repo.check-pipeline" $item1 }} {{- end }} + + - name: Set default branch for imported repositories + ansible.builtin.uri: + url: https://{{ $.Values.gitlab.host }}/api/v4/projects/{{ $item.name }}%2F{{ "{{" }} item.name {{ "}}" }} + method: PUT + body_format: form-urlencoded + body: + default_branch: '{{ "{{" }} item.defaultBranch {{ "}}" }}' + headers: + PRIVATE-TOKEN: '{{ "{{" }} root_token {{ "}}" }}' + validate_certs: false + status_code: + - 200 + retries: 10 + delay: 5 + register: r_default_branch + until: r_default_branch.status == 200 + when: item.defaultBranch != 'main' + loop: +{{- range $item1 := $item.repo }} + - name: {{ $item1.name }} + defaultBranch: {{ $item1.defaultBranch | default "main" }} +{{- end }} {{- end }} {{- if $item.project }} {{- range $item1 := $item.project }} - - name: Create project for group + - name: Create project {{ $item1.name }} for group ansible.builtin.uri: url: https://{{ $.Values.gitlab.host }}/api/v4/projects method: POST @@ -170,11 +235,27 @@ data: headers: PRIVATE-TOKEN: '{{ "{{" }} root_token {{ "}}" }}' validate_certs: false - status_code: 201 - retries: 100 + status_code: + - 201 + - 400 + - 409 + retries: 10 delay: 5 + register: r_create_project_result + until: r_create_project_result.status in [201, 400, 409] + failed_when: + - r_create_project_result.status == 400 + - "'has already been taken' not in (r_create_project_result.json | default({}) | string)" + + - name: Look up project {{ $item1.name }} + ansible.builtin.uri: + url: https://{{ $.Values.gitlab.host }}/api/v4/projects/{{ $item.name }}%2F{{ $item1.name }} + method: GET + headers: + PRIVATE-TOKEN: '{{ "{{" }} root_token {{ "}}" }}' + validate_certs: false + status_code: 200 register: r_create_project - until: r_create_project.status == 201 {{- if $item1.labels }} @@ -189,11 +270,13 @@ data: headers: PRIVATE-TOKEN: '{{ "{{" }} root_token {{ "}}" }}' validate_certs: false - status_code: 201 - retries: 100 + status_code: + - 201 + - 409 + retries: 10 delay: 5 register: r_create_label - until: r_create_label.status == 201 + until: r_create_label.status in [201, 409] loop: {{- range $item2 := $item1.labels }} - name: {{ $item2.name }} @@ -206,7 +289,7 @@ data: {{- if $item.users }} {{- range $item1 := $item.users }} - - name: Add user to group + - name: Add user {{ $item1.id }} to group when: item.username == '{{ $item1.id }}' ansible.builtin.uri: url: https://{{ $.Values.gitlab.host }}/api/v4/groups/{{ "{{" }} r_group.json.id {{ "}}" }}/members @@ -218,11 +301,13 @@ data: headers: PRIVATE-TOKEN: '{{ "{{" }} root_token {{ "}}" }}' validate_certs: false - status_code: 201 + status_code: + - 201 + - 409 register: r_group_user - retries: 100 + retries: 10 delay: 5 - until: r_group_user.status == 201 + until: r_group_user.status in [201, 409] or r_group_user is skipped loop: '{{ "{{" }} r_users.json {{ "}}" }}' {{- end }} {{- end }} @@ -253,5 +338,34 @@ data: pod: {{ .Values.vault.namespace }}-0 command: '{{ "{{" }} item {{ "}}" }}' loop: - - 'vault kv put kv/secrets/rhdh/gitlab token={{ "{{" }} root_token {{ "}}" }}' - - 'vault kv put kv/secrets/rhdh/gitlab_webhook secret={{ "{{" }} webhook_secret {{ "}}" }}' + - 'vault kv put kv/secrets/gitlab/token value={{ "{{" }} root_token {{ "}}" }}' + - 'vault kv put kv/secrets/gitlab/webhook-secret value={{ "{{" }} webhook_secret {{ "}}" }}' + + - name: Create GitLab OAuth application for DevSpaces + ansible.builtin.uri: + url: https://{{ $.Values.gitlab.host }}/api/v4/applications + method: POST + body_format: form-urlencoded + body: + name: devspaces + redirect_uri: "https://devspaces.{{ $.Values.cluster.subdomain }}/api/oauth/callback" + scopes: "api read_user read_repository write_repository openid profile email" + confidential: "true" + headers: + PRIVATE-TOKEN: '{{ "{{" }} root_token {{ "}}" }}' + validate_certs: false + status_code: + - 200 + - 201 + register: r_devspaces_oauth_app + retries: 10 + delay: 5 + until: r_devspaces_oauth_app.status in [200, 201] + + - name: Store DevSpaces GitLab OAuth credentials in Vault + kubernetes.core.k8s_exec: + namespace: {{ .Values.vault.namespace }} + pod: {{ .Values.vault.namespace }}-0 + command: '{{ "{{" }} item {{ "}}" }}' + loop: + - 'vault kv put kv/secrets/gitlab/devspaces-oauth id={{ "{{" }} r_devspaces_oauth_app.json.application_id {{ "}}" }} secret={{ "{{" }} r_devspaces_oauth_app.json.secret {{ "}}" }}' diff --git a/gitlab/templates/cm-gitlab-templates.yaml b/gitlab/templates/cm-gitlab-templates.yaml index 0d7ce83..19d47dc 100644 --- a/gitlab/templates/cm-gitlab-templates.yaml +++ b/gitlab/templates/cm-gitlab-templates.yaml @@ -70,26 +70,24 @@ data: {{- range $item1 := $item.templates }} - - name: Fetch /tmp/{{ $item.project }}/{{ $item1 }} template from remote host - run_once: true - ansible.builtin.fetch: - src: /tmp/{{ $item.project }}/{{ $item1 }} - dest: /tmp/{{ $item1 }} - flat: true - fail_on_missing: true - - - name: Apply template /tmp/{{ $item.project }}/{{ $item1 }} - ansible.builtin.template: - src: /tmp/{{ $item1 }} - dest: /tmp/{{ $item.project }}/{{ $item1 }} - mode: "0660" - vars: - gitlab_host: "{{ $.Values.gitlab.host }}" - cluster_subdomain: "{{ $.Values.cluster.subdomain }}" - rhdh_gitops_namespace: "{{ $.Values.gitops.namespace }}" - rhdh_gitops_project: "{{ $.Values.gitops.project }}" - quay_host: "{{ $.Values.quay.host }}" - orchestrator_namespace: "{{ $.Values.orchestrator.namespace }}" + - name: Replace template variables in /tmp/{{ $item.project }}/{{ $item1 }} + ansible.builtin.replace: + path: /tmp/{{ $item.project }}/{{ $item1 }} + regexp: '\{\{\s*{{ "{{" }} item.key {{ "}}" }}\s*\}\}' + replace: '{{ "{{" }} item.value {{ "}}" }}' + loop: + - key: gitlab_host + value: "{{ $.Values.gitlab.host }}" + - key: cluster_subdomain + value: "{{ $.Values.cluster.subdomain }}" + - key: rhdh_gitops_namespace + value: "{{ $.Values.gitops.namespace }}" + - key: rhdh_gitops_project + value: "{{ $.Values.gitops.project }}" + - key: quay_host + value: "{{ $.Values.quay.host }}" + - key: orchestrator_namespace + value: "{{ $.Values.orchestrator.namespace }}" {{- end }} - name: Add new files to the repository @@ -104,7 +102,7 @@ data: chdir: >- /tmp/{{ $item.project }} cmd: >- - git commit -a -m 'Updates for starting scenario.' + git commit -a -m 'gitlab init: updates for starting scenario.' ignore_errors: true - name: Push all changes back to the project repository diff --git a/gitlab/values.yaml b/gitlab/values.yaml index 498ff86..d465e2e 100644 --- a/gitlab/values.yaml +++ b/gitlab/values.yaml @@ -34,16 +34,25 @@ gitlab: repo: - name: template-quarkus-simple url: https://github.com/redhat-pe-workshop/rhdh-template-quarkus-simple.git + defaultBranch: dev - name: parasol-store-dev-template url: https://github.com/redhat-pe-workshop/parasol-store-dev-templates.git + defaultBranch: dev - name: parasol-store-dev-template-secure url: https://github.com/redhat-pe-workshop/parasol-store-dev-template-secured.git + defaultBranch: dev - name: developer-hub-config url: https://github.com/redhat-pe-workshop/developer-hub-config.git + - name: dh-config + url: https://github.com/redhat-ads-tech/rhdh-config.git - name: import-existing-app-template url: https://github.com/redhat-pe-workshop/import-existing-app-template.git + defaultBranch: dev - name: import-existing-api-template url: https://github.com/redhat-pe-workshop/import-api-template.git + defaultBranch: dev + - name: devfiles + url: https://github.com/redhat-pe-workshop/devfiles.git - name: rhdh-entities url: https://github.com/redhat-pe-workshop/pe-workshop-entities.git - name: template-developer-self-service @@ -106,17 +115,27 @@ gitlab: templates: - group: rhdh project: template-quarkus-simple - branch: main + branch: dev templates: - template.yaml - group: rhdh project: import-existing-app-template - branch: main + branch: dev templates: - template.yaml - group: rhdh project: import-existing-api-template - branch: main + branch: dev + templates: + - template.yaml + - group: rhdh + project: parasol-store-dev-template + branch: dev + templates: + - template.yaml + - group: rhdh + project: parasol-store-dev-template-secure + branch: dev templates: - template.yaml - group: global diff --git a/keycloak/keycloak-realm-import/templates/_helpers.tpl b/keycloak/keycloak-realm-import/templates/_helpers.tpl index 66c7303..8af9400 100644 --- a/keycloak/keycloak-realm-import/templates/_helpers.tpl +++ b/keycloak/keycloak-realm-import/templates/_helpers.tpl @@ -98,6 +98,17 @@ Backstage client secret {{- end }} {{- end }} +{{/* +OpenShift client secret +*/}} +{{- define "keycloak-realmimport.client-openshift-secret" -}} +{{- if .Values.client.openshift.secret }} +{{- .Values.client.openshift.secret }} +{{- else }} +{{- randAlphaNum 32 }} +{{- end }} +{{- end }} + {{/* User password */}} diff --git a/keycloak/keycloak-realm-import/templates/keycloak-realmimport.yaml b/keycloak/keycloak-realm-import/templates/keycloak-realmimport.yaml index b4ce4ca..d60c374 100644 --- a/keycloak/keycloak-realm-import/templates/keycloak-realmimport.yaml +++ b/keycloak/keycloak-realm-import/templates/keycloak-realmimport.yaml @@ -687,6 +687,47 @@ spec: - phone - offline_access - microprofile-jwt + - id: {{ uuidv4 }} + clientId: {{ .Values.client.openshift.name }} + surrogateAuthRequired: false + enabled: true + alwaysDisplayInConsole: false + clientAuthenticatorType: client-secret + secret: {{ include "keycloak-realmimport.client-openshift-secret" . }} + redirectUris: + - {{ .Values.client.openshift.redirectUri }} + webOrigins: + - '*' + notBefore: 0 + bearerOnly: false + consentRequired: false + standardFlowEnabled: true + implicitFlowEnabled: false + directAccessGrantsEnabled: true + serviceAccountsEnabled: false + publicClient: false + frontchannelLogout: true + protocol: openid-connect + attributes: + oidc.ciba.grant.enabled: 'false' + backchannel.logout.session.required: 'true' + display.on.consent.screen: 'false' + oauth2.device.authorization.grant.enabled: 'false' + backchannel.logout.revoke.offline.tokens: 'false' + authenticationFlowBindingOverrides: {} + fullScopeAllowed: true + nodeReRegistrationTimeout: -1 + defaultClientScopes: + - profile + - roles + - email + - web-origins + optionalClientScopes: + - acr + - address + - phone + - offline_access + - microprofile-jwt - id: {{ uuidv4 }} clientId: {{ .Values.client.backstagePlugin.name }} surrogateAuthRequired: false diff --git a/keycloak/keycloak-realm-import/values.yaml b/keycloak/keycloak-realm-import/values.yaml index aa054ed..92d2930 100644 --- a/keycloak/keycloak-realm-import/values.yaml +++ b/keycloak/keycloak-realm-import/values.yaml @@ -64,6 +64,10 @@ client: redirectUri: webOrigin: secret: + openshift: + name: openshift + redirectUri: "" + secret: trustedartifactsigner: name: trusted-artifact-signer redirectUri: diff --git a/openshift-oauth/Chart.yaml b/openshift-oauth/Chart.yaml new file mode 100644 index 0000000..91b2ca3 --- /dev/null +++ b/openshift-oauth/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: openshift-oauth +description: Configures OpenShift OAuth with Keycloak as an OpenID Connect identity provider +type: application +version: 0.1.0 diff --git a/openshift-oauth/templates/es-oidc-client-secret.yaml b/openshift-oauth/templates/es-oidc-client-secret.yaml new file mode 100644 index 0000000..a0300bf --- /dev/null +++ b/openshift-oauth/templates/es-oidc-client-secret.yaml @@ -0,0 +1,22 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: openshift-oidc-client-secret + namespace: openshift-config + {{- if and .Values.argocd .Values.argocd.enabled }} + annotations: + argocd.argoproj.io/sync-wave: {{ .Values.argocd.syncwave | quote }} + {{- end }} +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-secret-store + kind: ClusterSecretStore + target: + name: openshift-oidc-client-secret + creationPolicy: Owner + data: + - secretKey: clientSecret + remoteRef: + key: secrets/keycloak/openshift-client-secret + property: value diff --git a/openshift-oauth/templates/oauth.yaml b/openshift-oauth/templates/oauth.yaml new file mode 100644 index 0000000..1478b7a --- /dev/null +++ b/openshift-oauth/templates/oauth.yaml @@ -0,0 +1,34 @@ +# Adds Keycloak as an OpenID Connect identity provider ("developers") to the +# cluster OAuth CR. DevSpaces on OpenShift always authenticates via OpenShift +# OAuth (the operator hardcodes provider="openshift" in the gateway proxy +# config), so this is also how workshop users log into DevSpaces. +apiVersion: config.openshift.io/v1 +kind: OAuth +metadata: + name: cluster +spec: + identityProviders: + - name: htpasswd + mappingMethod: claim + type: HTPasswd + htpasswd: + fileData: + name: htpasswd + - name: developers + mappingMethod: claim + type: OpenID + openID: + clientID: {{ .Values.oidc.clientId }} + clientSecret: + name: openshift-oidc-client-secret + issuer: https://{{ .Values.keycloak.host }}/realms/{{ .Values.keycloak.realm }} + claims: + preferredUsername: + - preferred_username + email: + - email + name: + - name + extraScopes: + - email + - profile diff --git a/openshift-oauth/values.yaml b/openshift-oauth/values.yaml new file mode 100644 index 0000000..9d8ae5c --- /dev/null +++ b/openshift-oauth/values.yaml @@ -0,0 +1,10 @@ +keycloak: + host: "" + realm: backstage + +oidc: + clientId: openshift + +argocd: + enabled: true + syncwave: "3" diff --git a/orchestrator/orchestrator/templates/orchestrator-backstage-backend-token.yaml b/orchestrator/orchestrator/templates/orchestrator-backstage-backend-token.yaml index cb6ba60..98d0245 100644 --- a/orchestrator/orchestrator/templates/orchestrator-backstage-backend-token.yaml +++ b/orchestrator/orchestrator/templates/orchestrator-backstage-backend-token.yaml @@ -1,11 +1,25 @@ -apiVersion: v1 -kind: Secret +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret metadata: name: {{ include "orchestrator.name" . }}-backstage-backend-token namespace: {{ include "orchestrator.namespace" . }} annotations: {{- include "orchestrator.argocd-syncwave" . | nindent 4 }} -type: opaque -stringData: - BACKSTAGE_BACKEND_BEARER_TOKEN: {{ .Values.backstage.backend.token }} - BACKSTAGE_BACKEND_URL: {{ .Values.backstage.backend.url }} +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-secret-store + kind: ClusterSecretStore + target: + name: {{ include "orchestrator.name" . }}-backstage-backend-token + creationPolicy: Owner + template: + engineVersion: v2 + data: + BACKSTAGE_BACKEND_BEARER_TOKEN: {{ printf "{{ .token }}" | quote }} + BACKSTAGE_BACKEND_URL: {{ .Values.backstage.backend.url | quote }} + data: + - secretKey: token + remoteRef: + key: secrets/rhdh/orchestrator-token + property: value diff --git a/orchestrator/orchestrator/templates/orchestrator-ocp-gitlab-secret.yaml b/orchestrator/orchestrator/templates/orchestrator-ocp-gitlab-secret.yaml index 2013ca7..200b370 100644 --- a/orchestrator/orchestrator/templates/orchestrator-ocp-gitlab-secret.yaml +++ b/orchestrator/orchestrator/templates/orchestrator-ocp-gitlab-secret.yaml @@ -1,11 +1,25 @@ -apiVersion: v1 -kind: Secret +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret metadata: name: {{ include "orchestrator.name" . }}-gitlab-token namespace: {{ include "orchestrator.namespace" . }} annotations: {{- include "orchestrator.argocd-syncwave" . | nindent 4 }} -type: opaque -stringData: - GITLAB_TOKEN: {{ .Values.gitlab.token }} - GITLAB_URL: {{ .Values.gitlab.url }} +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-secret-store + kind: ClusterSecretStore + target: + name: {{ include "orchestrator.name" . }}-gitlab-token + creationPolicy: Owner + template: + engineVersion: v2 + data: + GITLAB_TOKEN: {{ printf "{{ .token }}" | quote }} + GITLAB_URL: {{ .Values.gitlab.url | quote }} + data: + - secretKey: token + remoteRef: + key: secrets/gitlab/token + property: value diff --git a/orchestrator/orchestrator/templates/orchestrator-ocp-token-secret.yaml b/orchestrator/orchestrator/templates/orchestrator-ocp-token-secret.yaml index 4ae18d9..a5bc4b0 100644 --- a/orchestrator/orchestrator/templates/orchestrator-ocp-token-secret.yaml +++ b/orchestrator/orchestrator/templates/orchestrator-ocp-token-secret.yaml @@ -1,11 +1,25 @@ -apiVersion: v1 -kind: Secret +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret metadata: name: {{ include "orchestrator.name" . }}-ocp-token namespace: {{ include "orchestrator.namespace" . }} annotations: {{- include "orchestrator.argocd-syncwave" . | nindent 4 }} -type: opaque -stringData: - OCP_API_SERVER_TOKEN: {{ .Values.openshift.token }} - OCP_API_SERVER_URL: {{ .Values.openshift.url }} +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-secret-store + kind: ClusterSecretStore + target: + name: {{ include "orchestrator.name" . }}-ocp-token + creationPolicy: Owner + template: + engineVersion: v2 + data: + OCP_API_SERVER_TOKEN: {{ printf "{{ .token }}" | quote }} + OCP_API_SERVER_URL: {{ .Values.openshift.url | quote }} + data: + - secretKey: token + remoteRef: + key: secrets/rhdh/kubernetes-sa-token + property: value diff --git a/orchestrator/orchestrator/values.yaml b/orchestrator/orchestrator/values.yaml index f19ad21..88617f4 100644 --- a/orchestrator/orchestrator/values.yaml +++ b/orchestrator/orchestrator/values.yaml @@ -3,19 +3,15 @@ backstage: operator: enabled: false backend: - token: url: openshift: - token: url: gitlab: - token: url: argocd: enabled: true orchestrator: syncwave: "0" - diff --git a/parasol/parasol-build/templates/job-parasol-store-build.yaml b/parasol/parasol-build/templates/job-parasol-store-build.yaml index 9ca44b3..8be9d1f 100644 --- a/parasol/parasol-build/templates/job-parasol-store-build.yaml +++ b/parasol/parasol-build/templates/job-parasol-store-build.yaml @@ -8,6 +8,7 @@ spec: backoffLimit: 100 template: spec: + serviceAccountName: parasol containers: - name: parasol-store-build command: diff --git a/parasol/parasol-build/templates/parasol-store-build-manifests.yaml b/parasol/parasol-build/templates/parasol-store-build-manifests.yaml index 0e489b3..7ff6946 100644 --- a/parasol/parasol-build/templates/parasol-store-build-manifests.yaml +++ b/parasol/parasol-build/templates/parasol-store-build-manifests.yaml @@ -114,7 +114,7 @@ data: chdir: >- /tmp/{{ $item.project }} cmd: >- - git commit -a -m 'Updates for starting scenario.' + git commit -a -m 'parasol init: updates for starting scenario.' ignore_errors: true - name: Push all changes back to the project repository diff --git a/parasol/parasol-build/values.yaml b/parasol/parasol-build/values.yaml index 15091f3..942c5f6 100644 --- a/parasol/parasol-build/values.yaml +++ b/parasol/parasol-build/values.yaml @@ -20,7 +20,7 @@ parasol: - argocd/app-build.yaml argocd: name: parasol-store-build - namespace: + namespace: rhdh-gitops image: name: parasol-store gitlab: diff --git a/parasol/parasol-templates/templates/job-parasol-store-templates.yaml b/parasol/parasol-templates/templates/job-parasol-store-templates.yaml index 5c580af..c65441d 100644 --- a/parasol/parasol-templates/templates/job-parasol-store-templates.yaml +++ b/parasol/parasol-templates/templates/job-parasol-store-templates.yaml @@ -8,6 +8,7 @@ spec: backoffLimit: 100 template: spec: + serviceAccountName: parasol containers: - name: parasol-templates command: diff --git a/parasol/parasol-templates/templates/parasol-store-templates.yaml b/parasol/parasol-templates/templates/parasol-store-templates.yaml index 2d59447..91f8b94 100644 --- a/parasol/parasol-templates/templates/parasol-store-templates.yaml +++ b/parasol/parasol-templates/templates/parasol-store-templates.yaml @@ -103,7 +103,7 @@ data: chdir: >- /tmp/{{ $item.project }} cmd: >- - git commit -a -m 'Updates for starting scenario.' + git commit -a -m 'parasol init: updates for starting scenario.' ignore_errors: true - name: Push all changes back to the project repository diff --git a/parasol/parasol/templates/crb-parasol-argocd.yaml b/parasol/parasol/templates/crb-parasol-argocd.yaml new file mode 100644 index 0000000..5472a70 --- /dev/null +++ b/parasol/parasol/templates/crb-parasol-argocd.yaml @@ -0,0 +1,37 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: parasol-argocd-applications + annotations: + argocd.argoproj.io/sync-wave: "-1" + labels: + app: parasol +rules: + - apiGroups: + - argoproj.io + resources: + - applications + verbs: + - create + - delete + - get + - list + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: parasol-argocd-applications + annotations: + argocd.argoproj.io/sync-wave: "-1" + labels: + app: parasol +subjects: + - kind: ServiceAccount + name: parasol + namespace: {{ $.Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: parasol-argocd-applications diff --git a/parasol/parasol/templates/job-parasol-db.yaml b/parasol/parasol/templates/job-parasol-db.yaml index ffc96df..17828dc 100644 --- a/parasol/parasol/templates/job-parasol-db.yaml +++ b/parasol/parasol/templates/job-parasol-db.yaml @@ -8,6 +8,7 @@ spec: backoffLimit: 100 template: spec: + serviceAccountName: parasol containers: - name: parasol-db command: diff --git a/parasol/parasol/templates/job-parasol-images.yaml b/parasol/parasol/templates/job-parasol-images.yaml index 23b62f3..334b61d 100644 --- a/parasol/parasol/templates/job-parasol-images.yaml +++ b/parasol/parasol/templates/job-parasol-images.yaml @@ -8,6 +8,7 @@ spec: backoffLimit: 100 template: spec: + serviceAccountName: parasol containers: - name: skopeo command: diff --git a/parasol/parasol/templates/job-parasol-store.yaml b/parasol/parasol/templates/job-parasol-store.yaml index f2b1f68..70abf52 100644 --- a/parasol/parasol/templates/job-parasol-store.yaml +++ b/parasol/parasol/templates/job-parasol-store.yaml @@ -8,6 +8,7 @@ spec: backoffLimit: 100 template: spec: + serviceAccountName: parasol containers: - name: parasol-store command: diff --git a/parasol/parasol/templates/job-parasol-web.yaml b/parasol/parasol/templates/job-parasol-web.yaml index 58c2252..a80627d 100644 --- a/parasol/parasol/templates/job-parasol-web.yaml +++ b/parasol/parasol/templates/job-parasol-web.yaml @@ -8,6 +8,7 @@ spec: backoffLimit: 100 template: spec: + serviceAccountName: parasol containers: - name: parasol-web command: diff --git a/parasol/parasol/templates/parasol-db-manifests.yaml b/parasol/parasol/templates/parasol-db-manifests.yaml index e1526b0..4bad4a6 100644 --- a/parasol/parasol/templates/parasol-db-manifests.yaml +++ b/parasol/parasol/templates/parasol-db-manifests.yaml @@ -96,7 +96,7 @@ data: chdir: >- /tmp/{{ $item.project }} cmd: >- - git commit -a -m 'Updates for starting scenario.' + git commit -a -m 'parasol init: updates for starting scenario.' ignore_errors: true - name: Push all changes back to the project repository diff --git a/parasol/parasol/templates/parasol-store-manifests.yaml b/parasol/parasol/templates/parasol-store-manifests.yaml index e280ef9..01988a5 100644 --- a/parasol/parasol/templates/parasol-store-manifests.yaml +++ b/parasol/parasol/templates/parasol-store-manifests.yaml @@ -103,7 +103,7 @@ data: chdir: >- /tmp/{{ $item.project }} cmd: >- - git commit -a -m 'Updates for starting scenario.' + git commit -a -m 'parasol init: updates for starting scenario.' ignore_errors: true - name: Push all changes back to the project repository diff --git a/parasol/parasol/templates/parasol-web-manifests.yaml b/parasol/parasol/templates/parasol-web-manifests.yaml index d19de5d..517ba94 100644 --- a/parasol/parasol/templates/parasol-web-manifests.yaml +++ b/parasol/parasol/templates/parasol-web-manifests.yaml @@ -107,7 +107,7 @@ data: chdir: >- /tmp/{{ $item.project }} cmd: >- - git commit -a -m 'Updates for starting scenario.' + git commit -a -m 'parasol init: : updates for starting scenario.' ignore_errors: true - name: Push all changes back to the project repository diff --git a/parasol/parasol/templates/rb-parasol.yaml b/parasol/parasol/templates/rb-parasol.yaml new file mode 100644 index 0000000..70082d5 --- /dev/null +++ b/parasol/parasol/templates/rb-parasol.yaml @@ -0,0 +1,14 @@ +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: parasol-admin + annotations: + argocd.argoproj.io/sync-wave: "-1" +subjects: + - kind: ServiceAccount + name: parasol + namespace: {{ $.Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: admin diff --git a/parasol/parasol/templates/sa-parasol.yaml b/parasol/parasol/templates/sa-parasol.yaml new file mode 100644 index 0000000..0a84840 --- /dev/null +++ b/parasol/parasol/templates/sa-parasol.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: parasol + annotations: + argocd.argoproj.io/sync-wave: "-2" + labels: + app: parasol diff --git a/parasol/parasol/values.yaml b/parasol/parasol/values.yaml index a2e72bb..ac9b3db 100644 --- a/parasol/parasol/values.yaml +++ b/parasol/parasol/values.yaml @@ -32,7 +32,7 @@ parasol: - app/argocd/app.yaml argocd: name: parasol-db - namespace: + namespace: rhdh-gitops store: templates: - project: parasol-store-manifests @@ -61,7 +61,7 @@ parasol: - app/argocd/app.yaml argocd: name: parasol-store - namespace: + namespace: rhdh-gitops image: source: image: quay.io/redhat_pe_workshop/parasol-store @@ -108,7 +108,7 @@ parasol: - app/argocd/app.yaml argocd: name: parasol-web - namespace: + namespace: rhdh-gitops image: source: image: quay.io/redhat_pe_workshop/parasol-web diff --git a/quay/quay-registry/templates/cm-config.yaml b/quay/quay-registry/templates/cm-config.yaml index edd13a3..f94ae91 100644 --- a/quay/quay-registry/templates/cm-config.yaml +++ b/quay/quay-registry/templates/cm-config.yaml @@ -147,9 +147,9 @@ data: pod: {{ .Values.vault.namespace }}-0 command: '{{ "{{" }} item {{ "}}" }}' loop: - - 'vault kv put kv/secrets/rhdh/registry/auth value={{ "{{" }} quay_auth | b64encode {{ "}}" }}' - - "vault kv put kv/secrets/rhdh/registry/username value={{ .Values.quay.adminUser }}" - - "vault kv put kv/secrets/rhdh/registry/password value={{ .Values.quay.adminUserPassword }}" + - 'vault kv put kv/secrets/quay/auth value={{ "{{" }} quay_auth | b64encode {{ "}}" }}' + - "vault kv put kv/secrets/quay/username value={{ .Values.quay.adminUser }}" + - "vault kv put kv/secrets/quay/password value={{ .Values.quay.adminUserPassword }}" {{- range $item := .Values.quay.organizations }} - name: Create organization {{ $item }} @@ -163,4 +163,34 @@ data: body_format: json validate_certs: false status_code: 201 +{{- end }} + +{{- range $user := .Values.quay.users }} + - name: Create user {{ $user.username }} + ansible.builtin.uri: + url: '{{ "{{" }} r_quay_registry.resources[0].status.registryEndpoint {{ "}}" }}/api/v1/superuser/users/' + method: POST + headers: + Authorization: 'Bearer {{ "{{" }} r_quayadmin.json.access_token {{ "}}" }}' + body: + username: {{ $user.username }} + email: {{ $user.email }} + body_format: json + validate_certs: false + status_code: + - 200 + register: r_create_user_{{ $user.username }} + + - name: Set password for {{ $user.username }} + ansible.builtin.uri: + url: '{{ "{{" }} r_quay_registry.resources[0].status.registryEndpoint {{ "}}" }}/api/v1/superuser/users/{{ $user.username }}' + method: PUT + headers: + Authorization: 'Bearer {{ "{{" }} r_quayadmin.json.access_token {{ "}}" }}' + body: + password: {{ $user.password }} + body_format: json + validate_certs: false + status_code: + - 200 {{- end }} \ No newline at end of file diff --git a/quay/quay-registry/values.yaml b/quay/quay-registry/values.yaml index b66ad67..6b95974 100644 --- a/quay/quay-registry/values.yaml +++ b/quay/quay-registry/values.yaml @@ -52,6 +52,7 @@ quay: cpu: 125m memory: 1Gi organizations: [] + users: [] noobaa: diff --git a/redhat-developer-hub/redhat-developer-hub-application/values.yaml b/redhat-developer-hub/redhat-developer-hub-application/values.yaml index 797fefc..438b2bc 100644 --- a/redhat-developer-hub/redhat-developer-hub-application/values.yaml +++ b/redhat-developer-hub/redhat-developer-hub-application/values.yaml @@ -6,7 +6,7 @@ gitops: helm: repo: https://charts.openshift.io chart: redhat-developer-hub - version: 1.8.0 + version: 1.8.2 values: git: host: diff --git a/redhat-developer-hub/redhat-developer-hub-config-template/templates/rhdh-config-template.yaml b/redhat-developer-hub/redhat-developer-hub-config-template/templates/rhdh-config-template.yaml index 9995aad..b392118 100644 --- a/redhat-developer-hub/redhat-developer-hub-config-template/templates/rhdh-config-template.yaml +++ b/redhat-developer-hub/redhat-developer-hub-config-template/templates/rhdh-config-template.yaml @@ -89,9 +89,6 @@ data: argocd_host: "{{ $.Values.gitops.host }}" kubernetes_api_url: "{{ $.Values.kubernetes.api }}" backstage_backend_secret: {{ randAlphaNum 24 | b64enc }} - oauth2_proxy_cookie_secret: {{ randAlpha 32 | lower | b64enc }} - oauth2_proxy_oidc_issuer: "{{ $.Values.oauth2.issuer }}" - orchestrator_sonataflow_data_index_service: "{{ $.Values.orchestrator.sonataFlowDataIndexService }}" {{- end }} - name: Add new files to the repository @@ -106,7 +103,7 @@ data: chdir: >- /tmp/{{ $item.project }} cmd: >- - git commit -a -m 'Updates for starting scenario.' + git commit -a -m 'rhdh init: updates for starting scenario.' ignore_errors: true - name: Push all changes back to the project repository diff --git a/redhat-developer-hub/redhat-developer-hub-config-template/values.yaml b/redhat-developer-hub/redhat-developer-hub-config-template/values.yaml index c69f213..7877d6a 100644 --- a/redhat-developer-hub/redhat-developer-hub-config-template/values.yaml +++ b/redhat-developer-hub/redhat-developer-hub-config-template/values.yaml @@ -32,9 +32,6 @@ gitops: kubernetes: api: -oauth2: - issuer: - cluster: subdomain: diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/cluster-role-binding-default-sa-admin.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/cluster-role-binding-default-sa-admin.yaml index daec266..ff14a74 100644 --- a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/cluster-role-binding-default-sa-admin.yaml +++ b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/cluster-role-binding-default-sa-admin.yaml @@ -1,12 +1,12 @@ kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: cluster-admin-default-{{ .Values.namespace }} + name: cluster-admin-default-{{ .Release.Namespace }} annotations: {{- include "redhat-developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} subjects: - kind: ServiceAccount - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} name: default roleRef: apiGroup: rbac.authorization.k8s.io diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/cm-sa-token-writer.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/cm-sa-token-writer.yaml new file mode 100644 index 0000000..0d4740d --- /dev/null +++ b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/cm-sa-token-writer.yaml @@ -0,0 +1,83 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: sa-token-writer + labels: + {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} + annotations: + argocd.argoproj.io/sync-wave: "1" +data: + playbook.yaml: | + --- + - name: Write SA token to Vault + hosts: localhost + vars: + namespace: {{ .Release.Namespace }} + vault_namespace: {{ .Values.vault.namespace }} + vault_name: {{ .Values.vault.name }} + tasks: + - name: Create service account token secret + kubernetes.core.k8s: + state: present + definition: + apiVersion: v1 + kind: Secret + type: kubernetes.io/service-account-token + metadata: + name: default-token + namespace: '{{ "{{" }} namespace {{ "}}" }}' + annotations: + kubernetes.io/service-account.name: default + + - name: Wait for token to be populated + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + name: default-token + namespace: '{{ "{{" }} namespace {{ "}}" }}' + register: r_token_secret + retries: 60 + delay: 5 + until: + - r_token_secret.resources is defined + - r_token_secret.resources | length > 0 + - r_token_secret.resources[0].data is defined + - r_token_secret.resources[0].data.token is defined + - r_token_secret.resources[0].data.token | length > 0 + + - name: Decode token + ansible.builtin.set_fact: + sa_token: '{{ "{{" }} r_token_secret.resources[0].data.token | b64decode {{ "}}" }}' + + - name: Retrieve Vault Pod + kubernetes.core.k8s_info: + kind: Pod + name: '{{ "{{" }} vault_name {{ "}}" }}-0' + namespace: '{{ "{{" }} vault_namespace {{ "}}" }}' + register: r_vault + retries: 120 + delay: 5 + until: + - r_vault.resources is defined + - r_vault.resources | length > 0 + - r_vault.resources[0].status is defined + - r_vault.resources[0].status.phase is defined + - r_vault.resources[0].status.phase == 'Running' + + - name: Read Vault token + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + name: vault-token + namespace: '{{ "{{" }} vault_namespace {{ "}}" }}' + register: r_vault_token + + - name: Set Vault token + ansible.builtin.set_fact: + vault_token: '{{ "{{" }} r_vault_token.resources[0].data.token | b64decode {{ "}}" }}' + + - name: Write SA token to Vault + kubernetes.core.k8s_exec: + namespace: '{{ "{{" }} vault_namespace {{ "}}" }}' + pod: '{{ "{{" }} vault_name {{ "}}" }}-0' + command: 'sh -c "VAULT_TOKEN={{ "{{" }} vault_token {{ "}}" }} vault kv put kv/secrets/rhdh/kubernetes-sa-token value={{ "{{" }} sa_token {{ "}}" }}"' diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-argocd-password.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-argocd-password.yaml new file mode 100644 index 0000000..d17811b --- /dev/null +++ b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-argocd-password.yaml @@ -0,0 +1,21 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: argocd-password + labels: + {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} + annotations: + {{- include "redhat-developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-secret-store + kind: ClusterSecretStore + target: + name: argocd-password + creationPolicy: Owner + data: + - secretKey: ARGOCD_PASSWORD + remoteRef: + key: secrets/rhdh/argocd-password + property: value diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-gitlab-token.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-gitlab-token.yaml new file mode 100644 index 0000000..b29381c --- /dev/null +++ b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-gitlab-token.yaml @@ -0,0 +1,21 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: gitlab-token + labels: + {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} + annotations: + {{- include "redhat-developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-secret-store + kind: ClusterSecretStore + target: + name: gitlab-token + creationPolicy: Owner + data: + - secretKey: GITLAB_TOKEN + remoteRef: + key: secrets/gitlab/token + property: value diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-kubernetes-sa-token.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-kubernetes-sa-token.yaml new file mode 100644 index 0000000..78c6c2e --- /dev/null +++ b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-kubernetes-sa-token.yaml @@ -0,0 +1,21 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: kubernetes-sa-token + labels: + {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} + annotations: + argocd.argoproj.io/sync-wave: "2" +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-secret-store + kind: ClusterSecretStore + target: + name: kubernetes-sa-token + creationPolicy: Owner + data: + - secretKey: KUBERNETES_SA_TOKEN + remoteRef: + key: secrets/rhdh/kubernetes-sa-token + property: value diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-oauth-client.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-oauth-client.yaml new file mode 100644 index 0000000..c84dbff --- /dev/null +++ b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-oauth-client.yaml @@ -0,0 +1,25 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: oauth-client + labels: + {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} + annotations: + {{- include "redhat-developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-secret-store + kind: ClusterSecretStore + target: + name: oauth-client + creationPolicy: Owner + data: + - secretKey: OAUTH_CLIENT_ID + remoteRef: + key: secrets/keycloak/client-secret + property: clientId + - secretKey: OAUTH_CLIENT_SECRET + remoteRef: + key: secrets/keycloak/client-secret + property: clientSecret diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-orchestrator-token.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-orchestrator-token.yaml new file mode 100644 index 0000000..062dd56 --- /dev/null +++ b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-orchestrator-token.yaml @@ -0,0 +1,21 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: backstage-orchestrator-token + labels: + {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} + annotations: + {{- include "redhat-developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-secret-store + kind: ClusterSecretStore + target: + name: backstage-orchestrator-token + creationPolicy: Owner + data: + - secretKey: ORCHESTRATOR_TOKEN + remoteRef: + key: secrets/rhdh/orchestrator-token + property: value diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-postgresql.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-postgresql.yaml new file mode 100644 index 0000000..0d44846 --- /dev/null +++ b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/es-postgresql.yaml @@ -0,0 +1,25 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ include "redhat-developer-hub-prereqs.name" . }}-postgresql + labels: + {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} + annotations: + {{- include "redhat-developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-secret-store + kind: ClusterSecretStore + target: + name: {{ include "redhat-developer-hub-prereqs.name" . }}-postgresql + creationPolicy: Owner + data: + - secretKey: postgres-password + remoteRef: + key: secrets/rhdh/postgresql-password + property: value + - secretKey: adminPasswordKey + remoteRef: + key: secrets/rhdh/postgresql-password + property: value diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/job-sa-token.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/job-sa-token.yaml new file mode 100644 index 0000000..e89d15a --- /dev/null +++ b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/job-sa-token.yaml @@ -0,0 +1,29 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: sa-token-writer + labels: + {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} + annotations: + argocd.argoproj.io/sync-wave: "1" + argocd.argoproj.io/hook: Sync + argocd.argoproj.io/hook-delete-policy: BeforeHookCreation +spec: + backoffLimit: 10 + template: + spec: + serviceAccountName: default + restartPolicy: OnFailure + containers: + - name: sa-token-writer + image: quay.io/agnosticd/ee-multicloud:latest + command: + - ansible-playbook + - /playbook/playbook.yaml + volumeMounts: + - name: playbook + mountPath: /playbook + volumes: + - name: playbook + configMap: + name: sa-token-writer diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-argocd-password.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-argocd-password.yaml deleted file mode 100644 index 467fc89..0000000 --- a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-argocd-password.yaml +++ /dev/null @@ -1,11 +0,0 @@ -kind: Secret -apiVersion: v1 -metadata: - name: argocd-password - labels: - {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} - annotations: - {{- include "redhat-developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} -stringData: - ARGOCD_PASSWORD: {{ .Values.backstage.argocd.password }} -type: Opaque diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-gitlab-token.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-gitlab-token.yaml deleted file mode 100644 index c559db3..0000000 --- a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-gitlab-token.yaml +++ /dev/null @@ -1,11 +0,0 @@ -kind: Secret -apiVersion: v1 -metadata: - name: gitlab-token - labels: - {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} - annotations: - {{- include "redhat-developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} -stringData: - GITLAB_TOKEN: {{ .Values.backstage.gitlab.token }} -type: Opaque diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-kubernetes-sa-token.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-kubernetes-sa-token.yaml deleted file mode 100644 index eacea7a..0000000 --- a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-kubernetes-sa-token.yaml +++ /dev/null @@ -1,11 +0,0 @@ -kind: Secret -apiVersion: v1 -metadata: - name: kubernetes-sa-token - labels: - {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} - annotations: - {{- include "redhat-developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} -stringData: - KUBERNETES_SA_TOKEN: {{ .Values.backstage.kubernetes.sa_token }} -type: Opaque diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-npmrc.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-npmrc.yaml index cb8bf24..7046aac 100644 --- a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-npmrc.yaml +++ b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-npmrc.yaml @@ -7,5 +7,5 @@ metadata: annotations: {{- include "redhat-developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} stringData: - .npmrc: registry=https://npm.registry.redhat.com + .npmrc: '@redhat:registry=https://npm.registry.redhat.com' type: Opaque diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-oauth-client.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-oauth-client.yaml deleted file mode 100644 index 7dbd752..0000000 --- a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-oauth-client.yaml +++ /dev/null @@ -1,12 +0,0 @@ -kind: Secret -apiVersion: v1 -metadata: - name: oauth-client - labels: - {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} - annotations: - {{- include "redhat-developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} -stringData: - OAUTH_CLIENT_ID: {{ .Values.backstage.oauth.clientId }} - OAUTH_CLIENT_SECRET: {{ .Values.backstage.oauth.clientSecret }} -type: Opaque diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-orchestrator-token.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-orchestrator-token.yaml deleted file mode 100644 index 10416ed..0000000 --- a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-orchestrator-token.yaml +++ /dev/null @@ -1,10 +0,0 @@ -kind: Secret -apiVersion: v1 -metadata: - name: backstage-orchestrator-token - labels: - {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} - annotations: - {{- include "redhat-developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} -stringData: - ORCHESTRATOR_TOKEN: {{ .Values.backstage.orchestrator.token }} \ No newline at end of file diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-postgresql.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-postgresql.yaml deleted file mode 100644 index 3a67dc7..0000000 --- a/redhat-developer-hub/redhat-developer-hub-prereqs/templates/secret-backstage-postgresql.yaml +++ /dev/null @@ -1,12 +0,0 @@ -kind: Secret -apiVersion: v1 -metadata: - name: {{ include "redhat-developer-hub-prereqs.name" . }}-postgresql - labels: - {{- include "redhat-developer-hub-prereqs.labels" . | nindent 4 }} - annotations: - {{- include "redhat-developer-hub-prereqs.argocd-syncwave" . | nindent 4 }} -stringData: - postgres-password: {{ .Values.backstage.postgresql.password }} - adminPasswordKey: {{ .Values.backstage.postgresql.password }} -type: Opaque diff --git a/redhat-developer-hub/redhat-developer-hub-prereqs/values.yaml b/redhat-developer-hub/redhat-developer-hub-prereqs/values.yaml index c6745fc..ca25be8 100644 --- a/redhat-developer-hub/redhat-developer-hub-prereqs/values.yaml +++ b/redhat-developer-hub/redhat-developer-hub-prereqs/values.yaml @@ -2,20 +2,13 @@ nameOverride: "backstage" namespace: default +vault: + namespace: vault + name: vault + backstage: - argocd: - password: - gitlab: - token: - kubernetes: - sa_token: - oauth: - clientId: - clientSecret: postgresql: password: password - orchestrator: - token: rbacPolicy: - "p, role:default/location_read, catalog.entity.read, read, allow" diff --git a/vault/templates/cm-vault-setup.yaml b/vault/templates/cm-vault-setup.yaml index f7a97b6..1dcebbc 100644 --- a/vault/templates/cm-vault-setup.yaml +++ b/vault/templates/cm-vault-setup.yaml @@ -106,3 +106,25 @@ data: - name: Enable kv version 2 ansible.builtin.shell: | oc exec vault-0 -n {{ "{{" }} vault_namespace {{ "}}" }} -- vault secrets enable -version=2 kv + ignore_errors: true + + - name: Pre-populate known secrets + kubernetes.core.k8s_exec: + namespace: '{{ "{{" }} vault_namespace {{ "}}" }}' + pod: vault-0 + command: '{{ "{{" }} item {{ "}}" }}' + loop: + - 'vault kv put kv/secrets/gitlab/root-password value={{ $.Values.secrets.gitlab.rootPassword }}' + - 'vault kv put kv/secrets/keycloak/client-secret clientId={{ $.Values.secrets.keycloak.clientId }} clientSecret={{ $.Values.secrets.keycloak.clientSecret }}' + - 'vault kv put kv/secrets/keycloak/plugin-client-secret value={{ $.Values.secrets.keycloak.pluginClientSecret }}' + - 'vault kv put kv/secrets/keycloak/openshift-client-secret value={{ $.Values.secrets.keycloak.openshiftClientSecret }}' + - 'vault kv put kv/secrets/rhdh/argocd-password value={{ $.Values.secrets.common.password }}' + - 'vault kv put kv/secrets/rhdh/postgresql-password value={{ $.Values.secrets.rhdh.postgresqlPassword }}' + - 'vault kv put kv/secrets/rhdh/orchestrator-token value={{ $.Values.secrets.orchestrator.token }}' + - 'vault kv put kv/secrets/common/password value={{ $.Values.secrets.common.password }}' +{{- if $.Values.secrets.kafka.userPassword }} + - 'vault kv put kv/secrets/kafka/user-password value={{ $.Values.secrets.kafka.userPassword }}' +{{- end }} +{{- if and $.Values.secrets.litellm.apiUrl $.Values.secrets.litellm.apiKey }} + - 'vault kv put kv/secrets/litellm/credentials base_url={{ $.Values.secrets.litellm.apiUrl }} api_key={{ $.Values.secrets.litellm.apiKey }}' +{{- end }} diff --git a/vault/templates/cronjob-auto-unseal.yaml b/vault/templates/cronjob-auto-unseal.yaml new file mode 100644 index 0000000..feced08 --- /dev/null +++ b/vault/templates/cronjob-auto-unseal.yaml @@ -0,0 +1,107 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: vault-auto-unseal +spec: + schedule: "*/1 * * * *" + concurrencyPolicy: Forbid + successfulJobsHistoryLimit: 1 + failedJobsHistoryLimit: 1 + jobTemplate: + spec: + template: + spec: + serviceAccountName: vault + restartPolicy: Never + containers: + - name: unsealer + image: registry.redhat.io/openshift4/ose-cli:v4.7 + volumeMounts: + - mountPath: /vault-unseal-config + name: vault-unseal-config-volume + command: + - /bin/bash + - -c + - | + echo "=== Vault Auto-Unseal Check at $(date) ===" + + # Check if vault-0 pod exists + if ! oc get pod {{ include "vault.name" . }}-0 -n {{ .Release.Namespace }} &>/dev/null; then + echo "Vault pod {{ include "vault.name" . }}-0 not found, skipping..." + exit 0 + fi + + # Check vault status + echo "Checking Vault status..." + set +e + oc exec {{ include "vault.name" . }}-0 -n {{ .Release.Namespace }} -- vault status -tls-skip-verify + STATUS=$? + set -e + + echo "Status code: $STATUS" + + if [ $STATUS -eq 0 ]; then + echo "Vault is already unsealed and healthy" + exit 0 + elif [ $STATUS -eq 2 ]; then + echo "Vault is sealed, checking initialization status..." + + # Check if already initialized (keys file exists) + set +e + oc exec {{ include "vault.name" . }}-0 -n {{ .Release.Namespace }} -- test -f /vault/data/vault-auto-unseal-keys.txt + KEYS_EXISTS=$? + set -e + + if [ $KEYS_EXISTS -eq 0 ]; then + echo "Vault already initialized, unsealing with existing keys..." + oc exec {{ include "vault.name" . }}-0 -n {{ .Release.Namespace }} -- /bin/sh /vault/data/unseal.sh + + # Verify unseal succeeded + set +e + oc exec {{ include "vault.name" . }}-0 -n {{ .Release.Namespace }} -- vault status -tls-skip-verify + FINAL_STATUS=$? + set -e + + if [ $FINAL_STATUS -eq 0 ]; then + echo "Successfully unsealed Vault" + exit 0 + else + echo "Vault unseal failed (exit code: $FINAL_STATUS)" + exit 1 + fi + else + # Vault is not initialized - initialize it + echo "Initializing Vault for the first time..." + oc exec {{ include "vault.name" . }}-0 --namespace={{ .Release.Namespace }} -- vault operator init -format=yaml > /tmp/vault-auto-unseal-keys.txt + + echo "Copying unseal keys to Vault pod..." + cat /tmp/vault-auto-unseal-keys.txt | oc exec -i -n {{ .Release.Namespace }} {{ include "vault.name" . }}-0 -c {{ include "vault.name" . }} "--" sh -c "cat > /vault/data/vault-auto-unseal-keys.txt" + + echo "Copying unseal script to Vault pod..." + cat /vault-unseal-config/unseal.sh | oc exec -i -n {{ .Release.Namespace }} {{ include "vault.name" . }}-0 -c {{ include "vault.name" . }} "--" sh -c "cat > /vault/data/unseal.sh" + + echo "Unsealing Vault..." + oc exec {{ include "vault.name" . }}-0 --namespace={{ .Release.Namespace }} -- /bin/sh /vault/data/unseal.sh + + # Verify unsealing succeeded + set +e + oc exec {{ include "vault.name" . }}-0 --namespace={{ .Release.Namespace }} -- vault status -tls-skip-verify + FINAL_STATUS=$? + set -e + + if [ $FINAL_STATUS -eq 0 ]; then + echo "Vault successfully initialized and unsealed" + exit 0 + else + echo "Vault unseal verification failed" + exit 1 + fi + fi + else + echo "Vault status check failed with unexpected code: $STATUS" + exit 1 + fi + volumes: + - name: vault-unseal-config-volume + configMap: + name: vault-unseal-config diff --git a/vault/templates/job-unseal-vault.yaml b/vault/templates/job-unseal-vault.yaml deleted file mode 100644 index 8f10dcd..0000000 --- a/vault/templates/job-unseal-vault.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: unseal-volt -spec: - template: - spec: - containers: - - name: unseal-volt - command: - - /bin/bash - - -c - - | - echo "Wait for Vault Pod Readiness" - until oc get pod vault-0 -n vault -o jsonpath='{.status.conditions[?(@.type=="PodReadyToStartContainers")].status}' | grep -q True; do - echo "Waiting for Ready..." - sleep 2 - done - oc exec vault-0 --namespace=vault --stdin --tty -- vault operator init -format=yaml > /tmp/vault-auto-unseal-keys.txt - cat /tmp/vault-auto-unseal-keys.txt | oc exec -i -n vault vault-0 -c vault "--" sh -c "cat > /vault/data/vault-auto-unseal-keys.txt" - cat /vault-unseal-config/unseal.sh | oc exec -i -n vault vault-0 -c vault "--" sh -c "cat > /vault/data/unseal.sh" - oc exec vault-0 --namespace=vault --stdin --tty -- /bin/sh /vault/data/unseal.sh - image: registry.redhat.io/openshift4/ose-cli:v4.7 - volumeMounts: - - mountPath: /vault-unseal-config - name: vault-unseal-config-volume - restartPolicy: Never - serviceAccount: vault - volumes: - - name: vault-unseal-config-volume - configMap: - name: vault-unseal-config \ No newline at end of file diff --git a/vault/values.yaml b/vault/values.yaml index 865a31a..eceabdf 100644 --- a/vault/values.yaml +++ b/vault/values.yaml @@ -7,4 +7,23 @@ vault: auth: namespace: default - \ No newline at end of file +secrets: + gitlab: + rootPassword: "" + keycloak: + clientId: backstage + clientSecret: "" + pluginClientSecret: "" + openshiftClientSecret: "" + rhdh: + argocdPassword: "" + postgresqlPassword: "" + orchestrator: + token: "" + common: + password: "" + litellm: + apiUrl: "" + apiKey: "" + kafka: + userPassword: ""