JFROG PLATFORM: How to synchronize Kubernetes secrets from external providers (AWS, GCP, etc..) with JFrog Helm charts
These days we implement a lot of secrets with our applications, and managing them becomes a necessity. For this, many popular cloud and non-cloud providers such as AWS, GCP, HashiCorp and many more have implemented their own secret manager service, to help maintain and manage these secrets. And for that, External Secrets Operator comes into the picture.
ESO is an operator containing custom API resources, ExternalSecret and SecretStore, that helps fetch secrets from these providers, and create a native Kubernetes secret out of it, to use it with Helm values. This way we can use it to fetch secrets that contain Artifactory’s license, DB credentials or certificates.
In this article we will work with GCP’s secret manager, to extract an Artifactory license as an example, and use it in our Helm charts. This can work with any of ESO’s supported providers, as the API mechanism works the same way, so you can use this as a standard, and follow the other provider’s documentation to set up the SecretStore.
Before continuing with this article, we heavily recommend that you read about ESO first, to further understand how it works.
Prerequisites:
- An existing Secret manager in GCP.
- Editor role to have enough permissions to create certain IAM roles.
- A service account.
- gcloud cli
Note: Permissions might differ in different providers.
Creating a service account, with relevant iAM policy:
First we will need to create a service account, with a binded iAM policy, that allows it to access secrets in GCP’s Secret Manager.
- Create a service account called “external-secrets-sv”
gcloud iam service-accounts create external-secrets-sv
- Add the “roles/secretmanager.secretAccessor” policy to the service account:
gcloud projects add-iam-policy-binding YOUR-PROJECT-ID --member "serviceAccount:external-secrets-sv@YOUR-PROJECT-ID.iam.gserviceaccount.com" --role "roles/secretmanager.secretAccessor"
Creating a service account key secret:
In order for the SecretStore’s API to have access to the Secret Manager, you will need to pass the service account’s key as a native Kubernetes secret. This is a must for all other providers as well.
- Create a JSON file containing the service account keys:
gcloud iam service-accounts keys create key.json --iam-account=external-secrets@YOUR-PROJECT-ID.iam.gserviceaccount.com
- Create a Kubernetes secret containing the file’s content:
kubectl create secret generic gcpsm-secret --from-file=secret-access-credentials=key.json
Creating the SecretStore and ExternalSecret resources:
In our final step, we will be creating the resources we need, to grab the Artifactory license secret from the Secret Manager and create a native secret out of it, to use it with our chart. We will be building the resources using the additionalResources key, so we can always manage it with our values.yaml, but you may also deploy them separately as well.
- In your values.yaml (Or separately), add the SecretStore and ExternalSecret resources:
additionalResources: | apiVersion: external-secrets.io/v1beta1 kind: SecretStore metadata: name: secretstore-ashraf spec: provider: gcpsm: auth: secretRef: secretAccessKeySecretRef: name: gcpsm-secret key: secret-access-credentials projectID: YOUR-PROJECT-ID --- apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: external-secret-ashraf spec: refreshInterval: 1h secretStoreRef: name: secretstore-ashraf kind: SecretStore target: name: artifactory-license-secret creationPolicy: Owner dataFrom: - extract: key: ashrafk-test-secret
The SecretStore will use the secret that you created, containing the Service Account key, which has access to your Secret Manager, and it will access the project based on the project ID you provided.
The ExternalSecret will refer to the SecretStore API to reach the Secret Manager, it will then extract the secret called “ashrafk-test-secret” as specified under the dataFrom section, and it will automatically create for you a native Kubernetes secret called “artifactory-license-secret”, as specified under the “target” section. The secret contains only one key called “art.lic”, which contains the license’s value. Important to note this as we also need to specify that key in our Helm values.
Final Deployment:
With this, we have successfully synchronized our license secret from GCP’s Secret Manager, into our Kubernetes cluster. Now all we need to do is finish up our values.yaml to include the license secret “artifactory-license-secret”, which gets created by the ExternalSecret resource:
artifactory: replicaCount: 1 license: secret: artifactory-license-secret dataKey: art.lic additionalResources: | apiVersion: external-secrets.io/v1beta1 kind: SecretStore metadata: name: secretstore-ashraf spec: provider: gcpsm: auth: secretRef: secretAccessKeySecretRef: name: gcpsm-secret key: secret-access-credentials projectID: YOUR-PROJECT-ID --- apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: external-secret-ashraf spec: refreshInterval: 1h secretStoreRef: name: secretstore-ashraf kind: SecretStore target: name: artifactory-license-secret creationPolicy: Owner dataFrom: - extract: key: ashrafk-test-secret
Deploy the values.yaml file:
helm upgrade --install artifactory jfrog/artifactory -n test -f values.yaml