-
Notifications
You must be signed in to change notification settings - Fork 295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Configure tokens and credentials from secrets/envs #480
Comments
Another issue for the same problem #319 |
And another #211 |
And a PR: #226 |
And another PR: #233 |
I would say that the time has come to solve this problem. 😛 |
I have seen @ebrianne's solution and it seems more of a workaround than a real solution. The proposed solution forces to keep an entire configMap somewhere with confidential information and, to my knowledge, in this way integration with a vault is not possible. A more complete approach would be to allow to take tokens from environment variables (like Grafana or OAuth2 Proxy charts do for example). In this way, the ENV can be stored in secret and retrieved by a Vault. |
This is not much of a workaround. I would say maybe a partial solution. I am only targeting the communication secret here that the user can provide directly and use for example SealedSecrets for GitOps. I did not think about the config (as a ConfigMap) itself, is that much sensitive information? I believe this could still be done in a similar way by providing a secret and mounting it but that may require some changes in botkube. |
I prefer not to save secrets in a repo, even if in a SealedSecret. |
@PrasadG193 any update on this? |
@PrasadG193 @thijsdejong @vaibhavp could you please take a look? |
@pierluigilenoci I think this is straightforward, do you mind submitting PR? Let me know if you need any help |
I'm sorry @PrasadG193 but right now I don't have time to prepare a PR. 😞 |
@PrasadG193 any chances to see this fixed? |
@PrasadG193 any news about this? v0.12.4 is out but this is not implemented. |
@PrasadG193 could you please take a look? |
Botkube secrets configurationCommunication
# Communication settings
communications:
# Using existing Communication secret
existingSecretName: ""
# Settings for Slack
slack:
enabled: false
channel: 'SLACK_CHANNEL'
token: 'SLACK_API_TOKEN'
notiftype: short
# ...trimmed... To use already existing secret:
KubeconfigAvailable only on
kubeconfig:
# If true, enables overriding the kubernetes auth
enabled: false
# A base64 encoded kubeconfig that will be stored in a secret, mounted to the pod, and specified in the KUBECONFIG environment variable.
base64Config: ""
# A secret containing a kubeconfig to use.
existingSecret: "" Install against external k8s cluster:
BEWARE: Configuring the external k8s is tricky as we need to also set IMO remembering to set additionally
This could be address with #589, where we plan to get rid of global variables. Then we can start consuming @PrasadG193 @pkosiec do you agree? SSLssl: # For using custom SSL certificates
enabled: false # Set to true and specify cert path in the next line after uncommenting
#cert: # SSL Certificate file e.g certs/my-cert.crt NOTE: No option to specify an external secret. Will be fixed by #597 Ingress# Ingress settings to expose teams and lark endpoints
ingress:
create: false
annotations:
kubernetes.io/ingress.class: nginx
host: 'HOST'
tls:
enabled: false
secretName: '' SummaryIn general, Botkube is able to consume sensitive data from external secrets. The Communication data can be specified already in I also added short description about Secret format and opt to specify SSL via external Secret in #597 |
@mszostok thank you for your reply. As I wrote explicitly in the issue description:
The configuration you suggest still requires manual intervention to create the |
I used csi-secrets-store-provider-aws and csi-secrets-store-provider-azure to inject the secrets into the pods. |
Thanks for the feedback! Previously, the only option was to specify the sensitive data via Now, the only option to specify communicator configuration is to pass the whole configuration file. To expose the individual environment variable we would need to use some lib e.g. https://github.com/knadh/koanf. For now, (as a workaround?), you can use the vault.hashicorp.com/agent-inject: 'true'
vault.hashicorp.com/role: 'internal-app'
vault.hashicorp.com/agent-inject-secret-database-config.txt: 'internal/data/database/config'
vault.hashicorp.com/agent-inject-template-database-config.txt: |
{{- with secret "internal/data/database/config" -}}
postgresql://{{ .Data.data.username }}:{{ .Data.data.password }}@postgres:5432/wizard
{{- end -}}
spec:
// .. trimmed... (it's just an example data based on their tutorial) However, I will try to create a showcase with the project that you mentioned, before we will put more customization in place. Will keep you posted 👍 |
@mszostok I would like to do what you write for Hashicorp Vault using CSI and the default vaults of Cloud Providers (specifically AWS and Azure). |
I tested that with Secret Store CSI and Vault provider. It turns out that more than the environment variable, you need an option to attach a given volume with your configuration. It applies even if you want to use the Sync Secret feature:
source: https://secrets-store-csi-driver.sigs.k8s.io/topics/sync-as-kubernetes-secret.html However, you are able to do that even with the current Helm chart, as BotKube allows using other Kubernetes Secret. BotKube with Vault tutorialPrerequisiteInstall Vault in cluster according to this tutorial: https://learn.hashicorp.com/tutorials/vault/kubernetes-secret-store-driver#install-the-vault-helm-chart
Also, when configuring access, use: vault policy write internal-app - <<EOF
path "secret/data/comm_config" {
capabilities = ["read"]
}
EOF vault write auth/kubernetes/role/database \
bound_service_account_names=botkube-sa \
bound_service_account_namespaces=default \
policies=internal-app \
ttl=20m StepsClick to expand!
cat > /tmp/values.yaml << ENDOFFILE
extraObjects:
- apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: vault-database
spec:
provider: vault
secretObjects:
- data:
- key: comm_config.yaml
objectName: "comm-config"
secretName: communication
type: Opaque
parameters:
vaultAddress: "http://vault.default:8200"
roleName: "database"
objects: |
- objectName: "comm-config"
secretPath: "secret/data/comm_config"
secretKey: "data"
- kind: Pod
apiVersion: v1
metadata:
name: init-secret
spec:
serviceAccountName: botkube-sa
containers:
- image: alpine
name: init
volumeMounts:
- name: secrets-store-inline
mountPath: "/mnt/secrets-store"
readOnly: true
volumes:
- name: secrets-store-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "vault-database"
communications:
existingSecretName: "communication"
serviceAccount:
create: false
name: botkube-sa # this SA is pre-authorized to access vault-database
ENDOFFILE
ExplanationThe SecretProviderClass CR allows us to create the K8s Secret. This secret is created only when the Volume is mounted to some Pod. We create a BotKube with Vault tutorial (override Volume)This approach requires modifying the BotKube Helm chart: Click to expand!diff --git a/helm/botkube/templates/communicationsecret.yaml b/helm/botkube/templates/communicationsecret.yaml
index 84f881f..4e59516 100644
--- a/helm/botkube/templates/communicationsecret.yaml
+++ b/helm/botkube/templates/communicationsecret.yaml
@@ -1,4 +1,4 @@
-{{- if not .Values.communications.existingSecretName -}}
+{{- if not (or .Values.communications.existingSecretName .Values.communications.existingVolume) -}}
apiVersion: v1
kind: Secret
metadata:
diff --git a/helm/botkube/templates/deployment.yaml b/helm/botkube/templates/deployment.yaml
index 2e043da..a109b52 100644
--- a/helm/botkube/templates/deployment.yaml
+++ b/helm/botkube/templates/deployment.yaml
@@ -50,7 +50,13 @@ spec:
{{ end }}
volumeMounts:
- name: config-volume
- mountPath: "/config"
+ mountPath: "/config/resource_config.yaml"
+ subPath: "resource_config.yaml"
+ {{- if .Values.communications.existingVolume }}
+ - name: {{ .Values.communications.existingVolume.name }}
+ mountPath: "/config/comm_config.yaml"
+ subPath: "comm_config.yaml"
+ {{ end }}
{{- if .Values.config.ssl.enabled }}
- name: certs
mountPath: "/etc/ssl/certs"
@@ -89,8 +95,13 @@ spec:
sources:
- configMap:
name: {{ include "botkube.fullname" . }}-configmap
+ {{- if not .Values.communications.existingVolume }}
- secret:
name: {{ include "botkube.CommunicationsSecretName" . }}
+ {{ end }}
+ {{- if .Values.communications.existingVolume }}
+ -{{ toYaml .Values.communications.existingVolume | nindent 10 }}
+ {{ end }}
{{- if .Values.config.ssl.enabled }}
- name: certs
secret:
diff --git a/helm/botkube/values.yaml b/helm/botkube/values.yaml
index 94e02b0..0f2db7a 100644
--- a/helm/botkube/values.yaml
+++ b/helm/botkube/values.yaml
@@ -307,6 +307,9 @@ communications:
# # Here specify settings for each app, like Slack, Mattermost etc.
# # NOTE: Use setting format visible below.
existingSecretName: ""
+ # Using existing Volume where the Communication data is available.
+ # If used, the default and `existingSecretName` configuration is ignored.
+ existingVolume: {}
# Settings for Slack
slack:
Then we are able to specify such installation values: cat > /tmp/values.yaml << ENDOFFILE
extraObjects:
- apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: vault-database
spec:
provider: vault
parameters:
vaultAddress: "http://vault.default:8200"
roleName: "database"
objects: |
- objectName: "comm_config.yaml"
objectAlias: "comm_config.yaml"
secretPath: "secret/data/comm_config"
secretKey: "data"
communications:
existingVolume:
name: comm-config
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "vault-database"
serviceAccount:
create: false
name: botkube-sa # this SA is pre-authorized to access vault-database
ENDOFFILE helm install botkube -f /tmp/values.yaml ./helm/botkube As a result, the installation is simplified and more seamless. Other optionsAllow a generic volume mount: extraVolumes:
- name: comm-config
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "vault-database"
extraVolumeMounts:
- mountPath: /config # requires you to use some predefined path or you will need to override the `CONFIG_PATH` env.
name: comm-config However, this more complicated at the end as you also need to disable the default config volume and also ensure that the path of mounted volume matches the expected one, or have an option to override them. SummaryIMO changing the current Helm chart is not required. Having an option to use the external Kubernetes Secret is already a generic solution which can be used to configure communication data with different sources. @PrasadG193 @pkosiec @pierluigilenoci please share your thoughts. Cheers! |
##### ISSUE TYPE - Feature Pull Request - Documentation Pull Request ##### SUMMARY - Add option to specify external secret with SSL cert - Document Secret format for `kubeconfig`, `ssl`, and `communication` settings. Related issue: #480 ##### TESTING An option to specify external secret with SSL cert can be tested with `helm template`: 1. Checkout this PR: `gh pr checkout 597` 2. Run with external Secret: ```bash helm template ./helm/botkube/ --namespace botkube --set config.ssl.enabled=true --set config.ssl.existingSecretName=external-ssl-cert ``` See that there is only **one** Secret for communication, and for certs the `external-ssl-cert` name is used. 4. Run with auto created secret: ```bash helm template ./helm/botkube/ --namespace botkube --set config.ssl.enabled=true --set config.ssl.cert=ssl.crt ``` See that there are **two** Secrets, one for communication and one for SSL. Testing of already existing features were described in #480 (comment)
Nice investigation @mszostok 🚀 I agree, from my point of view current Helm configuration is flexible enough. Later we can introduce |
@mszostok some notes:
I understand the desire to change as little as possible but the proposed solution does not seem a viable path. Another example of a chart that does this: I want to add that @ebrianne had already done a PR to achieve this result. |
Yep, but this has pros and cons. In one place, you have a single source of truth. Additionally, you can see the whole config at once, which requires less cognitive overhead.
What is different? There is a single interface that has a multiple provider. Provided example should work in all cases. With the current Helm chart, the provided solution works pretty well, and you can use external sources. But, in general, I also agree with you 👍 I created and tested an implementation which:
With all of that, the extraObjects:
- apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: vault-database
spec:
provider: vault
secretObjects:
- data:
- key: token
objectName: "slack-token"
secretName: communication-slack
type: Opaque
parameters:
vaultAddress: "http://vault.default:8200"
roleName: "database"
objects: |
- objectName: "slack-token"
secretPath: "secret/data/slack"
secretKey: "token"
communications:
# Settings for Slack
slack:
enabled: true
channel: 'random'
notiftype: short
# token - specified via env
extraEnv:
- name: COMMUNICATION_SLACK_TOKEN
valueFrom:
secretKeyRef:
name: communication-slack
key: token
extraVolumeMounts:
- name: secrets-store-inline
mountPath: "/mnt/secrets-store"
readOnly: true
extraVolumes:
- name: secrets-store-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "vault-database" Where e.g. in Vault we have only the
Here is the implementation: Once the #593 will be merged, I will create a dedicated PR. I understand that this will fulfil your use-case in 100%? EDIT: PR ready for review: #601 |
@mszostok let's say that's okay for now. 👌🏻 |
##### ISSUE TYPE - Feature Pull Request ##### SUMMARY - Allows providing communicator configuration via env variables - Env variables have higher priority that config from file - Helm chart has: - `extraEnv` - `extraVolumeMounts` - `extraVolumes` Fixes #480 Related documentation: kubeshop/botkube-docs#82 ##### TESTING Unit test proves that the reading configuration works as expected. However, below you will find an e2e tutorial. **BotKube with Vault via CSI driver** 1. Create K8s cluster, e.g. k3s via `lima-vm`: `limactl start template://k3s` > **NOTE:** The CSI needs to be supported, on k3d is problematic: k3d-io/k3d#206. Alternative is to just not play with the CSI driver and create your own volume that will be mounted, e.g. with predefined secret. 2. Install Vault: ```bash helm repo add hashicorp https://helm.releases.hashicorp.com helm repo update helm install vault hashicorp/vault \ --set "server.dev.enabled=true" \ --set "injector.enabled=false" \ --set "csi.enabled=true" ``` 3. Set Slack token: ```bash kubectl exec -it vault-0 -- /bin/sh ``` ```bash vault kv put secret/slack token={token} ``` 4. Configure Kubernetes authentication: ```bash vault auth enable kubernetes vault write auth/kubernetes/config \ kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" ``` ```bash vault policy write internal-app - <<EOF path "secret/data/slack" { capabilities = ["read"] } EOF ``` ```bash vault write auth/kubernetes/role/database \ bound_service_account_names=botkube-sa \ bound_service_account_namespaces=default \ policies=internal-app \ ttl=20m ``` 5. Install the secrets store CSI driver: ```bash helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts helm install csi secrets-store-csi-driver/secrets-store-csi-driver --set syncSecret.enabled=true ``` 6. Create install parameters: ```bash cat > /tmp/values.yaml << ENDOFFILE extraObjects: - apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: vault-database spec: provider: vault secretObjects: - data: - key: token objectName: "slack-token" secretName: communication-slack type: Opaque parameters: vaultAddress: "http://vault.default:8200" roleName: "database" objects: | - objectName: "slack-token" secretPath: "secret/data/slack" secretKey: "token" communications: # Settings for Slack slack: enabled: true channel: 'random' notiftype: short # token - specified via env extraEnv: - name: COMMUNICATION_SLACK_TOKEN valueFrom: secretKeyRef: name: communication-slack key: token extraVolumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true extraVolumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "vault-database" image: registry: mszostok repository: botkube tag: env-test-v2 ENDOFFILE ``` 7. Checkout this PR: `gh pr checkout 601` 8. Install BotKube: ```bash helm install botkube -f /tmp/values.yaml ./helm/botkube ```
Hi, the PR was merged, and now new functionality is available on However, you can try it already with the develop version. To do that, follow this tutorial: https://www.botkube.io/configuration/communication/vault-csi/ |
Is your feature request related to a problem? Please describe.
To date, the chart cannot be used with a GitOps approach.
Describe the solution you'd like
Give the ability to configure tokens and credentials from the environment variables instead of explicitly including them in the configuration. In this way integration with secrets (and vaults) is possible.
Describe alternatives you've considered
No alternative
Additional context
Not relevant
The text was updated successfully, but these errors were encountered: