Giter Club home page Giter Club logo

vals-operator's Introduction

vals-operator

Vals-Operator

CI GoDoc Go Report Card GitHub GitHub release (latest by date) Artifact Hub

Vals-Operator is a Kubernetes operator that integrates external

Here at Digitalis we love vals, it's a tool we use daily to keep secrets stored securely. Inspired by it, we have created an operator to manage Kubernetes secrets. As Digitalis and our sister company AxonOps are data companies, we also added a set of features tailored for running databases.

vals-operator syncs secrets from any secrets store supported by vals into Kubernetes. Also, vals-operator supports database secrets as provider by the HashiCorp Vault Secret Engine.

Demo

You can watch this brief video on how it works:

YouTube

Mirroring secrets

We have also added the ability to copy secrets between namespaces. It uses the format ref+k8s://namespace/secret#key. This way you can keep secrets generated in one namespace in sync with any other namespace in the cluster.

Installation

You can use the helm chart to install vals-operator. First of all, add the repository to your helm installation:

helm repo add digitalis https://digitalis-io.github.io/helm-charts

You will need to provide the configuration to access the secrets store you decided on via either environment variables pre existing secrets.

# Example for Vault
helm upgrade --install vals-operator --create-namespace -n vals-operator \
  --set "env[0].name=VAULT_ROLE_ID,env[0].value=vals-operator" \
  --set "env[1].name=VAULT_SECRET_ID,env[1].value=my-secret-id" \
  --set "env[2].name=VAULT_ADDR,env[2].value=https://vault:8200"
  digitalis/vals-operator

# Example for AWS using a secret
kubectl create secret generic -n vals-operator aws-creds \
  --from-literal=AWS_ACCESS_KEY_ID=foo \
  --from-literal=AWS_SECRET_ACCESS_KEY=bar \
  --from-literal=AWS_DEFAULT_REGION=us-west-2

helm upgrade --install vals-operator --create-namespace -n vals-operator \
  --set "secretEnv[0].secretRef.name=aws-creds"  \
  digitalis/vals-operator

# Another example using a Google Cloud service account
kubectl create secret generic -n vals-operator google-creds \
  --from-file=credentials.json=/path/to/service_account.json

helm upgrade --install vals-operator --create-namespace -n vals-operator \
  --set "env[0].name=GOOGLE_APPLICATION_CREDENTIALS,env[0].value=/secret/credentials.json" \
  --set "env[1].name=GCP_PROJECT,env[1].value=my_project" \
  --set "volumes[0].name=creds,volumes[0].secret.secretName=google-creds" \
  --set "volumeMounts[0].name=creds,volumeMounts[0].mountPath=/secret" \
  digitalis/vals-operator

ℹī¸ Check out the documentation for further details and examples including EKS integration.

HashiCorp Vault Authentication

If you're using Vault as backend you can also enable the Kubernetes Auth login method. Refer to the HashiCorp documentation on creating a role.

You will need to add two additional environment variables to the vals-operator installation:

  • VAULT_ROLE_ID: required to enable Kubernetes Login
  • VAULT_ADDR: URL to the Vault server, ie, http://vault:8200
  • VAULT_LOGIN_USER and VAULT_LOGIN_PASSWORD: to use userpass authentication (insecure, not recommended)
  • VAULT_APP_ROLE and VAULT_SECRET_ID: to use approle authentication

Usage

apiVersion: digitalis.io/v1
kind: ValsSecret
metadata:
  name: vals-secret-sample
  labels:
    owner: digitalis.io
spec:
  name: my-secret # Optional, default is the resource name
  ttl: 3600       # Optional, default is 0. The secret will be checked at every "reconcile period". See below.
  type: Opaque    # Default type, others supported
  data:
    username:
      ref: ref+vault://secret/database/username
      encoding: text
    password:
      ref: ref+vault://secret/database/password
      encoding: text
    ssh:
      ref: ref+vault://secret/database/ssh-private-key
      encoding: base64
    aws-user:
      ref: ref+awssecrets://kube/test#username
    aws-pass:
      ref: ref+awssecrets://kube/test#password
    ns-secret:
      ref: ref+k8s://namespace/secret#key
    plain-text:
      ref: literal_name # this is not processed by any secrets agent but is added to the secret as a literal string
  template:
    config.yaml: |
      # Config generated by Vals-Operator on {{ now | date "2006-01-02" }}
      username: {{.username}}
      password: {{.password}}
      {{- if .url }}
      url: {{ .url | lower }}
      {{ end }}

The example above will create a secret named my-secret and get the values from the different sources. The secret will be kept in sync against the backed secrets store.

The TTL is optional and used to decrease the number of times the operator calls the backend secrets store as some of them such as AWS Secrets Manager will incur a cost.

The default encoding is text but you can change it to base64 per secret reference. This way you can, for example, base64 encode large configuration files. If you omit the ref+ prefix vals-operator will not process the string and it will be added to the secret as as literal string.

You may also use GoLang templates to format a secret. You can inject as variables any of the keys referenced in the data section to format, for example, a configuration file. The sprig functions are supported.

Vault database credentials


NOTE: Vault >= 1.10 is required for this feature to work


A great feature in HashiCorp Vault is the generate database credentials dynamically. The missing part is you need these credentials in Kubernertes where your applications are. This is why we have added a new resource definition to do just that:

apiVersion: digitalis.io/v1beta1
kind: DbSecret
metadata:
  name: cassandra
spec:
  renew: true # this is the default, otherwise a new credential will be generated every time
  vault:
    role: readonly
    mount: cass000
  template: # optional: change the secret format
    CASSANDRA_USERNAME: "{{ .username }}"
    CASSANDRA_PASSWORD: "{{ .password }}"
  rollout: # optional: run a `rollout` to make the pods use new credentials
    - kind: Deployment
      name: cassandra-client
    - kind: StatefulSet
      name: cassandra-client-other

Advance config: password rotation

If you're running a database you may want to keep the secrets in sync between your secrets store, Kubernetes and the database. This can be handy for password rotation to ensure the clients don't use the same password all the time. Please be aware your client must suppport re-reading the secret and reconnecting whenever it is updated.

We don't yet support TLS, we'll add it to future releases.

---
apiVersion: digitalis.io/v1
kind: ValsSecret
metadata:
  name: vals-secret-sample
  labels:
    owner: digitalis.io
spec:
  name: my-secret # Optional, default is the resource name
  ttl: 10         # Optional, default is 0. The secret will be checked at every "reconcile period". See below.
  type: Opaque    # Default type, others supported
  data:
    username:
      ref: ref+gcpsecrets://databases/test#username
      encoding: text
    password:
      ref: ref+gcpsecrets://databases/test#password
      encoding: text
  databases:
    - driver: cassandra
      loginCredentials:
        secretName: cassandra-creds # secret containing the username and password to access the DB and run the below query
        usernameKey: username       # in the secret, which key contains the username (default `cassandra`)
        passwordKey: password       # in the secret, which key contains the password
      port: 9042
      usernameKey: username
      passwordKey: password
      hosts:                        # list all your cassandra nodes here
        - cassandra01
        - cassandra02
    - driver: postgres
      loginCredentials:
        secretName: postgres-creds
        usernameKey: username
        passwordKey: password
      port: 5432
      usernameKey: username
      passwordKey: password
      hosts:
        - postgres
    - driver: mysql
      loginCredentials:
        secretName: mysql-creds
        namespace: mysql-server
        passwordKey: mysql-root-password # if username is omitted it defaults to `mysql`
      port: 3306
      usernameKey: username
      passwordKey: password
      userHost: "%"                     # default
      hosts:
        - mysql
    - driver: elastic
      loginCredentials:
        secretName: elastic-creds
        namespace: elastic-server
        usernameKey: username           # the username defaults to 'elastic' if not provided
        passwordKey: password
      port: 9200
      usernameKey: username
      passwordKey: password
      hosts:
        - my-elastic                    # this would be converted to http://my-elastic:9200
        - https://my-other-elastic:9200 # provide full URL instead

vals-operator's People

Contributors

89luca89 avatar digiserg avatar irasnyd avatar jspruyt avatar millerjp avatar rgooding avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

vals-operator's Issues

Issue with digitalisdocker/vals-operator:v0.6.0

Hi, trying install latest version with helm get an issue bellow:

Failed to pull image "digitalisdocker/vals-operator:v0.6.0": rpc error: code = Unknown desc = Error response from daemon: manifest for digitalisdocker/vals-operator:v0.6.0 not found: manifest unknown: manifest unknown

get parameter: ResourceNotFoundException: Secrets Manager can't find the specified secret

Hi,

I am testing vals-operator to see it can fit in our current setup. I was able to install the helm charts using the instructions. Created a secret to be used by helm charts.

When I was trying to create using object kind: ValsSecret, get the above error, even though the secret exit. I have created a secret kube.test#username and kube.test#password in our region. FYI, my secret name in AWS secret manager is kube.test having two fields username and password.

Default AWS region is same for helm secrets and the following secret.

apiVersion: digitalis.io/v1
kind: ValsSecret
metadata:
  name: vals-secret-sample
  labels:
    owner: digitalis.io
spec:
  name: my-secret # Optional, default is the resource name
  #ttl: 3600       # Optional, default is 0. The secret will be checked at every "reconcile period". See below.
  type: Opaque    # Default type, others supported
  data:
    aws-user:
      ref: ref+awssecrets://kube.test#username
    aws-pass:
      ref: ref+awssecrets://kube.test#password

Logs from the vals-operator pod,

1.6590061832090268e+09	ERROR	controllers.vals-operator	Failed to get secrets from secrets store	{"name": "vals-secret-sample", "error": "expand awssecrets://kube.test#username: get parameter: ResourceNotFoundException: Secrets Manager can't find the specified secret."}
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Reconcile
	/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:121
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler
	/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:320
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem
	/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:273
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func2.2
	/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:234
1.6590061832092552e+09	INFO	controllers.vals-operator	errorBackoff: 5.47083928s  (jitter=470.83928ms)
1.6590061832097049e+09	DEBUG	events	Normal	{"object": {"kind":"ValsSecret","namespace":"default","name":"vals-secret-sample","uid":"74c0c393-67c5-4736-bd98-3dd0d031ab28","apiVersion":"digitalis.io/v1","resourceVersion":"100782694"}, "reason": "Failed", "message": "Failed to get secrets from secrets store expand awssecrets://kube.test#username: get parameter: ResourceNotFoundException: Secrets Manager can't find the specified secret."}

Can someone please shed some light, I might be missing something here? Thanks

Regards,
Abdul

TLS connection to vault server doesn't work

Hi everyone,

I've tried to configure vals-operator to use TLS authentication for connecting to Vault server but it doesn't seem to be working.

Here is the piece of my values.yaml that I use to configure TLS:

env:
  - name: VAULT_ROLE_ID
    value: vals-operator
  - name: VAULT_ADDR
    value: https://vault.vault:8200
  - name: VAULT_CACERT
    value: /vault/userconfig/vault-server-tls/vault.ca
  - name: VAULT_CLIENT_CERT
    value: /vault/userconfig/vault-server-tls/vault.crt
  - name: VAULT_CLIENT_KEY
    value: /vault/userconfig/vault-server-tls/vault.key
  - name: VAULT_TLS_SERVER_NAME
    value: vault

volumes:
  - name: vault-server-tls
    secret:
      secretName: vault-server-tls
      defaultMode: 420
volumeMounts:
  - name: vault-server-tls
    mountPath: /vault/userconfig/vault-server-tls
    readOnly: true

Connection without TLS works fine if I set VAULT_SKIP_VERIFY to true.
I've also tested TLS connection manually using the same certificates stored in vault-server-tls secret and it works properly.

Unfortunately I didn't find a way to properly troubleshoot it because vals-operator is using distroless Docker image with no capabilities for using shell.

Error that I get in vals-operator logs is the following:

ERROR   vault   unable to authenticate to Vault {"error": "unable to login to kubernetes auth method: unable to log in to auth method: unable to log in with Kubernetes auth: Put \"https://vault.vault:8200/v1/auth/kubernetes/login\": x509: certificate signed by unknown authority"}

I would very appreciate your assistance with resolving this issue.

Thanks.

Best regards,
Roman Timoshevskii.

Template field missing in helmchart CRDs

I tried using the templating for ValsSecret when I noticed that my CRDs which was installed with helm hasn't been updated. And after looking at the chart in this repo it seems that the CRD might not have been regenerated after templating was added. Would it be possible to regenerate the CRD for the helmchart, as I would very much like to try out the new templating feature.

Allow a secret to exist on multiple namespaces

The change would allow the same secret to being synced to multiple namespaces. This can be very useful for secrets such as private docker registries. The new schema could look like the example below:

---
apiVersion: digitalis.io/v1
kind: ValsSecret
metadata:
  name: private-registry
spec:
  type: kubernetes.io/dockerconfigjson
  namespaces:
    - one
    - two
    - three
  data:
    auth:
      ref: "ref+vault://secret/registry/dockerconfigjson"
      encoding: text

Bug: some chars are not being parsed by the template

"level":"error","ts":"2024-02-06T11:06:48Z","logger":"controllers.vals-operator","msg":"Cannot parse template","error":"template: conf.yaml:1: bad character U+002D '-'","stacktrace":"digitalis.io/vals-operator/controllers.(*ValsSecretReconciler).Reconcile\n\t/workspace/controllers/valssecret_controller.go:203\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Reconcile\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:119\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:316\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:266\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func2.2\n\t/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:227"}

Permit combing secrets with raw data

For example,

---
apiVersion: digitalis.io/v1
kind: ValsSecret
metadata:
  name: my-secret
spec:
  ttl: 3600       # Optional, default is 0. The secret will be checked at every "reconcile period". See below.
  type: Opaque    # Default type, others supported
  data:
    username:
      ref: ref+vault://secret/username
      encoding: text
    password:
      ref: ref+vault://secret/password
      encoding: text
    server:
      plain: my-server.com

Add pre-commit github actions

To improve code quality, it would be good to add github actions to perform syntax and linting checks on pull requests

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤ī¸ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.