From f7f459728acbb9d7c2f1b77b44a0e8fe5e612b49 Mon Sep 17 00:00:00 2001 From: Rae Sharp Date: Thu, 12 Mar 2026 11:52:34 -0400 Subject: [PATCH 1/7] Secrets Proxy initial commit update vale update placement update auth --- docs/manuals/uxp/howtos/secrets-proxy.md | 391 +++++++++++++++++++++++ 1 file changed, 391 insertions(+) create mode 100644 docs/manuals/uxp/howtos/secrets-proxy.md diff --git a/docs/manuals/uxp/howtos/secrets-proxy.md b/docs/manuals/uxp/howtos/secrets-proxy.md new file mode 100644 index 00000000..6c99b9fc --- /dev/null +++ b/docs/manuals/uxp/howtos/secrets-proxy.md @@ -0,0 +1,391 @@ +--- +title: Use the Secrets Proxy +description: "Learn how to configure the Secrets Proxy to access secrets from an external Vault secret store" +sidebar_position: 50 +--- + +The Secrets Proxy lets Crossplane providers read and write secrets directly +to HashiCorp Vault instead of storing them as Kubernetes Secrets. Providers +use the standard Kubernetes Secret API — the proxy intercepts those calls and +routes them to Vault transparently. + +## Prerequisites + +Before you begin, ensure you have: + +* [kubectl](https://kubernetes.io/docs/tasks/tools/) installed +* [Helm](https://helm.sh/docs/intro/install/) installed +* The [Vault CLI](https://developer.hashicorp.com/vault/docs/install) installed +* The `up` CLI installed +* A UXP cluster running version 2.2 or later +* A HashiCorp Vault instance reachable from your cluster, with Kubernetes auth enabled + +:::tip +Don't have a Vault instance yet? See [Bootstrap a local test environment](#bootstrap-a-local-test-environment) at the end of this page. +::: + +## Enable the Secrets Proxy + +Enable the Secrets Proxy on your UXP installation: + +```shell +helm repo add upbound-stable https://charts.upbound.io/stable && helm repo update +``` + +```shell +helm install crossplane \ + --namespace crossplane-system \ + --create-namespace \ + upbound-stable/crossplane \ + --devel \ + --set upbound.secretsProxy.enabled=true +``` + +```shell +kubectl get pods -n crossplane-system -w +``` + +## Apply a development license + +```shell +up uxp license apply --dev +up uxp license show +``` + +## Configure Vault + +Store the secrets that providers will read, and create a policy granting the +Secrets Proxy access to them. + +1. Store AWS credentials in Vault. The Secrets Proxy serves these to providers + as if they were a Kubernetes Secret, using the `ini` format expected by the + AWS provider family: + + ```shell + vault kv put secret/crossplane-system/aws-official-creds credentials=" + [default] + aws_access_key_id = + aws_secret_access_key = + " + ``` + +2. Create a policy granting read access to secrets in `crossplane-system`: + + ```shell + vault policy write crossplane-policy - <<'EOF' + path "secret/data/crossplane-system/*" { + capabilities = ["read", "list"] + } + EOF + ``` + +## Configure Vault Kubernetes auth + +Configure Vault to trust service account tokens from your UXP cluster so the +Secrets Proxy sidecar can authenticate on behalf of provider pods. + +1. Create a service account for Vault token review: + + ```shell + kubectl create serviceaccount vault-auth -n crossplane-system + + kubectl create clusterrolebinding vault-auth-delegator \ + --clusterrole=system:auth-delegator \ + --serviceaccount=crossplane-system:vault-auth + ``` + +2. Generate a long-lived token for the reviewer service account: + + ```shell + REVIEWER_JWT=$(kubectl create token vault-auth \ + -n crossplane-system --duration=8760h) + ``` + +3. Retrieve the cluster CA certificate and API server URL: + + ```shell + KUBE_CA_CERT=$(kubectl config view --raw --minify --flatten \ + --output='jsonpath={.clusters[].cluster.certificate-authority-data}' \ + | base64 --decode) + + KUBE_HOST=$(kubectl config view --raw --minify --flatten \ + --output='jsonpath={.clusters[].cluster.server}') + ``` + +4. Enable the Kubernetes auth method and configure it with the cluster details: + + ```shell + vault auth enable kubernetes + + vault write auth/kubernetes/config \ + kubernetes_host="${KUBE_HOST}" \ + kubernetes_ca_cert="${KUBE_CA_CERT}" \ + token_reviewer_jwt="${REVIEWER_JWT}" + ``` + +5. Create a role that binds all service accounts in `crossplane-system` to the + policy: + + ```shell + vault write auth/kubernetes/role/crossplane \ + bound_service_account_names="*" \ + bound_service_account_namespaces="crossplane-system" \ + policies=crossplane-policy \ + ttl=1h + ``` + + +## Install the Secret Store add-on + +Apply the add-on to deploy the Secrets Proxy backend: + +```yaml title=addon.yaml +apiVersion: pkg.upbound.io/v1alpha1 +kind: AddOn +metadata: + name: secret-store-vault +spec: + package: xpkg.upbound.io/upbound/secret-store-vault-addon:v0.1.0 +``` + +```shell +kubectl apply -f addon.yaml +``` + +Once the add-on is ready, create a `StoreConfig` pointing to your Vault +instance: + +```yaml +apiVersion: vault.secrets.upbound.io/v1alpha1 +kind: StoreConfig +metadata: + name: vault +spec: + address: http://vault.vault-system.svc.cluster.local:8200 + mountPath: secret + kvVersion: KVv2 + auth: + method: kubernetes + kubernetes: + role: crossplane +``` + +```shell +kubectl apply -f storeconfig.yaml +kubectl get storeconfigs +``` + +## Configure the webhook + +Apply the webhook configuration to inject the Secrets Proxy sidecar into +Crossplane and provider pods. The webhook restarts all matching pods on apply: + +```yaml +apiVersion: secretsproxy.upbound.io/v1alpha1 +kind: WebhookConfig +metadata: + name: crossplane-app +spec: + objectSelector: + matchLabels: + app: crossplane +--- +apiVersion: secretsproxy.upbound.io/v1alpha1 +kind: WebhookConfig +metadata: + name: crossplane-provider +spec: + objectSelector: + matchExpressions: + - key: pkg.crossplane.io/provider + operator: Exists +``` + +```shell +kubectl apply -f webhookconfig.yaml +``` + +## Install providers and functions + +1. Install the AWS provider family and IAM provider. Provider pods start with + the Secrets Proxy sidecar injected because the webhook matches the + `pkg.crossplane.io/provider` label: + + ```yaml + apiVersion: pkg.crossplane.io/v1 + kind: Provider + metadata: + name: upbound-provider-aws-iam + spec: + package: xpkg.upbound.io/upbound/provider-aws-iam:v2.2.0 + ignoreCrossplaneConstraints: true + --- + apiVersion: pkg.crossplane.io/v1 + kind: Provider + metadata: + name: upbound-provider-family-aws + spec: + package: xpkg.upbound.io/upbound/provider-family-aws:v2.2.0 + ignoreCrossplaneConstraints: true + ``` + + ```shell + kubectl apply -f providers.yaml + ``` + +2. Install the pipeline functions: + + ```yaml + apiVersion: pkg.crossplane.io/v1 + kind: Function + metadata: + name: function-go-templating + spec: + package: xpkg.crossplane.io/crossplane-contrib/function-go-templating:v0.11.2 + --- + apiVersion: pkg.crossplane.io/v1 + kind: Function + metadata: + name: function-auto-ready + spec: + package: xpkg.crossplane.io/crossplane-contrib/function-auto-ready:v0.6.0 + ``` + + ```shell + kubectl apply -f functions.yaml + ``` + + +3. Wait for providers and functions to become healthy, then create the provider + config. The `aws-official-creds` secret lives in Vault. The Secrets Proxy + intercepts the Secret API call and serves it transparently: + + + ```yaml + apiVersion: aws.m.upbound.io/v1beta1 + kind: ClusterProviderConfig + metadata: + name: default + namespace: crossplane-system + spec: + credentials: + secretRef: + key: credentials + name: aws-official-creds + namespace: crossplane-system + source: Secret + ``` + + ```shell + kubectl apply -f provider-config.yaml + ``` + +## Deploy the composition + +Apply the `UserAccessKey` XRD and composition. This composition creates an IAM +user and two access keys, writing connection details back to Vault through the +Secrets Proxy: + +```shell +kubectl apply -f comp.yaml +``` + +## Create the composite resource + +1. Edit `xr.yaml` and replace `` with your initials in both + the `metadata.name` and `spec.writeConnectionSecretToRef.name` fields: + + ```yaml + apiVersion: example.org/v1alpha1 + kind: UserAccessKey + metadata: + namespace: default + name: -keys + spec: + writeConnectionSecretToRef: + name: -keys-connection-details + ``` + +2. Apply the resource and verify reconciliation: + + ```shell + kubectl apply -f xr.yaml + kubectl get managed + kubectl get composite + ``` + + Connection details are stored in Vault, not in Kubernetes. Confirm no new + secrets were created: + + ```shell + kubectl get secret -n crossplane-system + ``` + +## Clean up + +Delete the composite resource. The garbage collector automatically removes the +associated secrets from Vault: + +```shell +kubectl delete -f xr.yaml +``` + +## Bootstrap a local test environment + +If you don't have a Vault instance and UXP cluster, you can set one up locally +using Kind. + +### Create a Kind cluster + +```shell +kind create cluster --name crossplane-secrets || true +kind export kubeconfig --name crossplane-secrets +``` + +### Bootstrap Vault in dev mode + +Dev mode starts with a pre-configured root token and KV v2 secrets engine +enabled at `secret/`. It is not persistent and is only suitable for testing. + + +1. Add the HashiCorp Helm repo and install Vault: + + + ```shell + helm repo add hashicorp https://helm.releases.hashicorp.com + helm repo update + + helm upgrade --install vault hashicorp/vault \ + --namespace vault-system \ + --create-namespace \ + --set server.dev.enabled=true \ + --set server.dev.devRootToken=root + ``` + +2. Wait for the Vault pod to be ready: + + ```shell + kubectl wait statefulset/vault -n vault-system \ + --for=jsonpath='.status.readyReplicas'=1 --timeout=120s + ``` + +3. In a separate terminal, start the port-forward and leave it running: + + ```shell + kubectl port-forward svc/vault 8200:8200 -n vault-system + ``` + +4. Back in your original terminal, set your CLI environment variables: + + ```shell + export VAULT_ADDR=http://127.0.0.1:8200 + export VAULT_TOKEN=root + ``` + + +:::warning +Dev mode Vault is in-memory only. All data is lost when the pod restarts. +::: + + +Return to [Enable the Secrets Proxy](#enable-the-secrets-proxy) to continue. From 672bf1da1a46747af8c8adffa88da5568e0f5528 Mon Sep 17 00:00:00 2001 From: Rae Sharp Date: Thu, 12 Mar 2026 13:25:36 -0400 Subject: [PATCH 2/7] update helm command --- docs/manuals/uxp/howtos/secrets-proxy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manuals/uxp/howtos/secrets-proxy.md b/docs/manuals/uxp/howtos/secrets-proxy.md index 6c99b9fc..525dacdd 100644 --- a/docs/manuals/uxp/howtos/secrets-proxy.md +++ b/docs/manuals/uxp/howtos/secrets-proxy.md @@ -33,7 +33,7 @@ helm repo add upbound-stable https://charts.upbound.io/stable && helm repo updat ``` ```shell -helm install crossplane \ +helm upgrade --install crossplane \ --namespace crossplane-system \ --create-namespace \ upbound-stable/crossplane \ From 58e21e6b4e64338f4809d1c7a9abca09063db797 Mon Sep 17 00:00:00 2001 From: Rae Sharp Date: Thu, 12 Mar 2026 13:33:06 -0400 Subject: [PATCH 3/7] Update install/upgrade --- docs/manuals/uxp/howtos/secrets-proxy.md | 61 +----------------------- 1 file changed, 1 insertion(+), 60 deletions(-) diff --git a/docs/manuals/uxp/howtos/secrets-proxy.md b/docs/manuals/uxp/howtos/secrets-proxy.md index 525dacdd..e0bc6000 100644 --- a/docs/manuals/uxp/howtos/secrets-proxy.md +++ b/docs/manuals/uxp/howtos/secrets-proxy.md @@ -33,7 +33,7 @@ helm repo add upbound-stable https://charts.upbound.io/stable && helm repo updat ``` ```shell -helm upgrade --install crossplane \ +helm install crossplane \ --namespace crossplane-system \ --create-namespace \ upbound-stable/crossplane \ @@ -330,62 +330,3 @@ associated secrets from Vault: kubectl delete -f xr.yaml ``` -## Bootstrap a local test environment - -If you don't have a Vault instance and UXP cluster, you can set one up locally -using Kind. - -### Create a Kind cluster - -```shell -kind create cluster --name crossplane-secrets || true -kind export kubeconfig --name crossplane-secrets -``` - -### Bootstrap Vault in dev mode - -Dev mode starts with a pre-configured root token and KV v2 secrets engine -enabled at `secret/`. It is not persistent and is only suitable for testing. - - -1. Add the HashiCorp Helm repo and install Vault: - - - ```shell - helm repo add hashicorp https://helm.releases.hashicorp.com - helm repo update - - helm upgrade --install vault hashicorp/vault \ - --namespace vault-system \ - --create-namespace \ - --set server.dev.enabled=true \ - --set server.dev.devRootToken=root - ``` - -2. Wait for the Vault pod to be ready: - - ```shell - kubectl wait statefulset/vault -n vault-system \ - --for=jsonpath='.status.readyReplicas'=1 --timeout=120s - ``` - -3. In a separate terminal, start the port-forward and leave it running: - - ```shell - kubectl port-forward svc/vault 8200:8200 -n vault-system - ``` - -4. Back in your original terminal, set your CLI environment variables: - - ```shell - export VAULT_ADDR=http://127.0.0.1:8200 - export VAULT_TOKEN=root - ``` - - -:::warning -Dev mode Vault is in-memory only. All data is lost when the pod restarts. -::: - - -Return to [Enable the Secrets Proxy](#enable-the-secrets-proxy) to continue. From 6291a6708a9168d8734ee4b99c06053c378994d8 Mon Sep 17 00:00:00 2001 From: Rae Sharp Date: Thu, 12 Mar 2026 14:07:44 -0400 Subject: [PATCH 4/7] update placement --- docs/manuals/uxp/howtos/secrets-proxy.md | 150 +++++++++++++++++++---- 1 file changed, 125 insertions(+), 25 deletions(-) diff --git a/docs/manuals/uxp/howtos/secrets-proxy.md b/docs/manuals/uxp/howtos/secrets-proxy.md index e0bc6000..6f2e646e 100644 --- a/docs/manuals/uxp/howtos/secrets-proxy.md +++ b/docs/manuals/uxp/howtos/secrets-proxy.md @@ -54,30 +54,27 @@ up uxp license show ## Configure Vault -Store the secrets that providers will read, and create a policy granting the -Secrets Proxy access to them. +Store the AWS credentials that providers will read. The Secrets Proxy serves +these to providers as if they were a Kubernetes Secret, using the `ini` format +expected by the AWS provider family: -1. Store AWS credentials in Vault. The Secrets Proxy serves these to providers - as if they were a Kubernetes Secret, using the `ini` format expected by the - AWS provider family: - - ```shell - vault kv put secret/crossplane-system/aws-official-creds credentials=" - [default] - aws_access_key_id = - aws_secret_access_key = - " - ``` +```shell +vault kv put secret/crossplane-system/aws-official-creds credentials=" +[default] +aws_access_key_id = +aws_secret_access_key = +" +``` -2. Create a policy granting read access to secrets in `crossplane-system`: +Create a policy granting read access to secrets in `crossplane-system`: - ```shell - vault policy write crossplane-policy - <<'EOF' - path "secret/data/crossplane-system/*" { - capabilities = ["read", "list"] - } - EOF - ``` +```shell +vault policy write crossplane-policy - <<'EOF' +path "secret/data/crossplane-system/*" { + capabilities = ["read", "list"] +} +EOF +``` ## Configure Vault Kubernetes auth @@ -101,15 +98,16 @@ Secrets Proxy sidecar can authenticate on behalf of provider pods. -n crossplane-system --duration=8760h) ``` -3. Retrieve the cluster CA certificate and API server URL: +3. Retrieve the cluster CA certificate and API server URL. For local clusters + (Kind, minikube), use the in-cluster Kubernetes service address so Vault can + reach the API server from inside the cluster: ```shell KUBE_CA_CERT=$(kubectl config view --raw --minify --flatten \ --output='jsonpath={.clusters[].cluster.certificate-authority-data}' \ | base64 --decode) - KUBE_HOST=$(kubectl config view --raw --minify --flatten \ - --output='jsonpath={.clusters[].cluster.server}') + KUBE_HOST="https://kubernetes.default.svc.cluster.local" ``` 4. Enable the Kubernetes auth method and configure it with the cluster details: @@ -130,6 +128,7 @@ Secrets Proxy sidecar can authenticate on behalf of provider pods. vault write auth/kubernetes/role/crossplane \ bound_service_account_names="*" \ bound_service_account_namespaces="crossplane-system" \ + bound_audiences="https://kubernetes.default.svc.cluster.local" \ policies=crossplane-policy \ ttl=1h ``` @@ -140,7 +139,7 @@ Secrets Proxy sidecar can authenticate on behalf of provider pods. Apply the add-on to deploy the Secrets Proxy backend: ```yaml title=addon.yaml -apiVersion: pkg.upbound.io/v1alpha1 +apiVersion: pkg.upbound.io/v1beta1 kind: AddOn metadata: name: secret-store-vault @@ -286,6 +285,106 @@ Apply the `UserAccessKey` XRD and composition. This composition creates an IAM user and two access keys, writing connection details back to Vault through the Secrets Proxy: +```yaml title=comp.yaml +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: useraccesskeys-go-templating +spec: + compositeTypeRef: + apiVersion: example.org/v1alpha1 + kind: UserAccessKey + mode: Pipeline + pipeline: + - step: render-templates + functionRef: + name: function-go-templating + input: + apiVersion: gotemplating.fn.crossplane.io/v1beta1 + kind: GoTemplate + source: Inline + inline: + template: | + --- + apiVersion: iam.aws.m.upbound.io/v1beta1 + kind: User + metadata: + annotations: + {{ setResourceNameAnnotation "user" }} + spec: + forProvider: {} + --- + apiVersion: iam.aws.m.upbound.io/v1beta1 + kind: AccessKey + metadata: + annotations: + {{ setResourceNameAnnotation "accesskey-0" }} + spec: + forProvider: + userSelector: + matchControllerRef: true + writeConnectionSecretToRef: + name: {{ $.observed.composite.resource.metadata.name }}-accesskey-secret-0 + --- + apiVersion: iam.aws.m.upbound.io/v1beta1 + kind: AccessKey + metadata: + annotations: + {{ setResourceNameAnnotation "accesskey-1" }} + spec: + forProvider: + userSelector: + matchControllerRef: true + writeConnectionSecretToRef: + name: {{ $.observed.composite.resource.metadata.name }}-accesskey-secret-1 + --- + apiVersion: v1 + kind: Secret + metadata: + name: {{ dig "spec" "writeConnectionSecretToRef" "name" "" $.observed.composite.resource}} + annotations: + {{ setResourceNameAnnotation "connection-secret" }} + {{ if eq $.observed.resources nil }} + data: {} + {{ else }} + data: + user-0: {{ ( index $.observed.resources "accesskey-0" ).connectionDetails.username }} + user-1: {{ ( index $.observed.resources "accesskey-1" ).connectionDetails.username }} + password-0: {{ ( index $.observed.resources "accesskey-0" ).connectionDetails.password }} + password-1: {{ ( index $.observed.resources "accesskey-1" ).connectionDetails.password }} + {{ end }} + - step: ready + functionRef: + name: function-auto-ready +--- +apiVersion: apiextensions.crossplane.io/v2 +kind: CompositeResourceDefinition +metadata: + name: useraccesskeys.example.org +spec: + group: example.org + names: + kind: UserAccessKey + plural: useraccesskeys + scope: Namespaced + versions: + - name: v1alpha1 + served: true + referenceable: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + writeConnectionSecretToRef: + type: object + properties: + name: + type: string +``` + ```shell kubectl apply -f comp.yaml ``` @@ -330,3 +429,4 @@ associated secrets from Vault: kubectl delete -f xr.yaml ``` + From fb14c451adc2af16b9a6c588400a814c97500272 Mon Sep 17 00:00:00 2001 From: Rae Sharp Date: Thu, 12 Mar 2026 14:19:20 -0400 Subject: [PATCH 5/7] remove local test reference --- docs/manuals/uxp/howtos/secrets-proxy.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/manuals/uxp/howtos/secrets-proxy.md b/docs/manuals/uxp/howtos/secrets-proxy.md index 6f2e646e..97fe0f4a 100644 --- a/docs/manuals/uxp/howtos/secrets-proxy.md +++ b/docs/manuals/uxp/howtos/secrets-proxy.md @@ -20,10 +20,6 @@ Before you begin, ensure you have: * A UXP cluster running version 2.2 or later * A HashiCorp Vault instance reachable from your cluster, with Kubernetes auth enabled -:::tip -Don't have a Vault instance yet? See [Bootstrap a local test environment](#bootstrap-a-local-test-environment) at the end of this page. -::: - ## Enable the Secrets Proxy Enable the Secrets Proxy on your UXP installation: From 2d8d2fee168074aaa593258ca8fe69124bf2f4f2 Mon Sep 17 00:00:00 2001 From: Rae Sharp Date: Thu, 12 Mar 2026 15:02:45 -0400 Subject: [PATCH 6/7] update licensing --- docs/manuals/uxp/howtos/secrets-proxy.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/docs/manuals/uxp/howtos/secrets-proxy.md b/docs/manuals/uxp/howtos/secrets-proxy.md index 97fe0f4a..977acd45 100644 --- a/docs/manuals/uxp/howtos/secrets-proxy.md +++ b/docs/manuals/uxp/howtos/secrets-proxy.md @@ -17,7 +17,7 @@ Before you begin, ensure you have: * [Helm](https://helm.sh/docs/intro/install/) installed * The [Vault CLI](https://developer.hashicorp.com/vault/docs/install) installed * The `up` CLI installed -* A UXP cluster running version 2.2 or later +* A UXP cluster running version 2.2 or later and a valid license * A HashiCorp Vault instance reachable from your cluster, with Kubernetes auth enabled ## Enable the Secrets Proxy @@ -41,13 +41,6 @@ helm install crossplane \ kubectl get pods -n crossplane-system -w ``` -## Apply a development license - -```shell -up uxp license apply --dev -up uxp license show -``` - ## Configure Vault Store the AWS credentials that providers will read. The Secrets Proxy serves From 45932549f0145aee64b2c263c904a7058e12a980 Mon Sep 17 00:00:00 2001 From: Rae Sharp Date: Thu, 12 Mar 2026 15:11:03 -0400 Subject: [PATCH 7/7] update vale --- docs/manuals/uxp/howtos/secrets-proxy.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/manuals/uxp/howtos/secrets-proxy.md b/docs/manuals/uxp/howtos/secrets-proxy.md index 977acd45..b04a2ff7 100644 --- a/docs/manuals/uxp/howtos/secrets-proxy.md +++ b/docs/manuals/uxp/howtos/secrets-proxy.md @@ -6,7 +6,7 @@ sidebar_position: 50 The Secrets Proxy lets Crossplane providers read and write secrets directly to HashiCorp Vault instead of storing them as Kubernetes Secrets. Providers -use the standard Kubernetes Secret API — the proxy intercepts those calls and +use the standard Kubernetes Secret API. The Secrets Proxy intercepts those calls and routes them to Vault transparently. ## Prerequisites @@ -20,7 +20,9 @@ Before you begin, ensure you have: * A UXP cluster running version 2.2 or later and a valid license * A HashiCorp Vault instance reachable from your cluster, with Kubernetes auth enabled + ## Enable the Secrets Proxy + Enable the Secrets Proxy on your UXP installation: @@ -43,7 +45,7 @@ kubectl get pods -n crossplane-system -w ## Configure Vault -Store the AWS credentials that providers will read. The Secrets Proxy serves +Store the AWS credentials that the provider reads. The Secrets Proxy serves these to providers as if they were a Kubernetes Secret, using the `ini` format expected by the AWS provider family: