• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

external-secrets/kubernetes-external-secrets: Integrate external secret manageme ...

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称(OpenSource Name):

external-secrets/kubernetes-external-secrets

开源软件地址(OpenSource Url):

https://github.com/external-secrets/kubernetes-external-secrets

开源编程语言(OpenSource Language):

JavaScript 97.2%

开源软件介绍(OpenSource Introduction):

Deprecated

This project has been deprecated. Please take a look at ESO (External Secrets Operator) instead https://github.com/external-secrets/external-secrets

Artifact HUB LGTM Alerts

History

This project was moved from the GoDaddy to the external-secrets GitHub organization in an effort to consolidate different projects with the same objective. More information here.

Kubernetes External Secrets

Kubernetes External Secrets allows you to use external secret management systems, like AWS Secrets Manager or HashiCorp Vault, to securely add secrets in Kubernetes. Read more about the design and motivation for Kubernetes External Secrets on the GoDaddy Engineering Blog.

The community and maintainers of this project and related Kubernetes secret management projects use the #external-secrets channel on the Kubernetes slack for discussion and brainstorming.

How it works

The project extends the Kubernetes API by adding an ExternalSecrets object using Custom Resource Definition and a controller to implement the behavior of the object itself.

An ExternalSecret declares how to fetch the secret data, while the controller converts all ExternalSecrets to Secrets. The conversion is completely transparent to Pods that can access Secrets normally.

By default Secrets are not encrypted at rest and are open to attack, either via the etcd server or via backups of etcd data. To mitigate this risk, use an external secret management system with a KMS plugin to encrypt Secrets stored in etcd.

System architecture

Architecture

  1. ExternalSecrets are added in the cluster (e.g., kubectl apply -f external-secret-example.yml)
  2. Controller fetches ExternalSecrets using the Kubernetes API
  3. Controller uses ExternalSecrets to fetch secret data from external providers (e.g, AWS Secrets Manager)
  4. Controller upserts Secrets
  5. Pods can access Secrets normally

How to use it

Install with Helm

The official helm chart can be used to create the kubernetes-external-secrets resources and Deployment on a Kubernetes cluster using the Helm package manager.

$ helm repo add external-secrets https://external-secrets.github.io/kubernetes-external-secrets/
$ helm install [RELEASE_NAME] external-secrets/kubernetes-external-secrets

For more details about configuration see the helm chart docs

Install with kubectl

If you don't want to install helm on your cluster and just want to use kubectl to install kubernetes-external-secrets, you could get the helm client cli first and then use the following sample command to generate kubernetes manifests:

$ helm template --include-crds --output-dir ./output_dir external-secrets/kubernetes-external-secrets

The generated kubernetes manifests will be in ./output_dir and can be applied to deploy kubernetes-external-secrets to the cluster.

Secrets Manager access

For kubernetes-external-secrets to be able to retrieve your secrets it will need access to your secret backend.

AWS based backends

Access to AWS secrets backends (SSM & secrets manager) can be granted in various ways:

  1. Granting your nodes explicit access to your secrets using the node instance role (easy for experimentation, not recommended)

  2. IAM roles for service accounts.

  3. Per pod IAM authentication: kiam or kube2iam.

  4. Directly provide AWS access credentials to the kubernetes-external-secrets pod by environmental variables.

Optionally configure custom endpoints using environment variables

  • AWS_SM_ENDPOINT - Useful to set endpoints for FIPS compliance.
  • AWS_STS_ENDPOINT - Useful to set endpoints for FIPS compliance or regional latency.
  • AWS_SSM_ENDPOINT - Useful to set endpoints for FIPS compliance or custom VPC endpoint.
Using AWS access credentials

Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY env vars in the kubernetes-external-secrets session/pod. You can use envVarsFromSecret in the helm chart to create these env vars from existing k8s secrets.

Additionally, you can specify a roleArn which will be assumed before retrieving the secret. You can limit the range of roles which can be assumed by this particular namespace by using annotations on the namespace resource. The annotation key is configurable (see above). The annotation value is evaluated as a regular expression and tries to match the roleArn.

kind: Namespace
metadata:
  name: iam-example
  annotations:
    # annotation key is configurable
    iam.amazonaws.com/permitted: "arn:aws:iam::123456789012:role/.*"

Add a secret

Add your secret data to your backend. For example, AWS Secrets Manager:

aws secretsmanager create-secret --name hello-service/password --secret-string "1234"

AWS Parameter Store:

aws ssm put-parameter --name "/hello-service/password" --type "String" --value "1234"

and then create a hello-service-external-secret.yml file:

apiVersion: "kubernetes-client.io/v1"
kind: ExternalSecret
metadata:
  name: hello-service
spec:
  backendType: secretsManager
  # optional: specify role to assume when retrieving the data
  roleArn: arn:aws:iam::123456789012:role/test-role
  data:
    - key: hello-service/password
      name: password
  # optional: specify a template with any additional markup you would like added to the downstream Secret resource.
  # This template will be deep merged without mutating any existing fields. For example: you cannot override metadata.name.
  template:
    metadata:
      annotations:
        cat: cheese
      labels:
        dog: farfel

or

apiVersion: "kubernetes-client.io/v1"
kind: ExternalSecret
metadata:
  name: hello-service
spec:
  backendType: systemManager
  data:
    - key: /hello-service/password
      name: password

The following IAM policy allows a user or role to access parameters matching prod-*.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ssm:GetParameter",
      "Resource": "arn:aws:ssm:us-west-2:123456789012:parameter/prod-*"
    }
  ]
}

The IAM policy for Secrets Manager is similar (see docs):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetResourcePolicy",
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret",
        "secretsmanager:ListSecretVersionIds"
      ],
      "Resource": [
        "arn:aws:secretsmanager:us-west-2:111122223333:secret:aes128-1a2b3c",
        "arn:aws:secretsmanager:us-west-2:111122223333:secret:aes192-4D5e6F",
        "arn:aws:secretsmanager:us-west-2:111122223333:secret:aes256-7g8H9i"
      ]
    }
  ]
}

Save the file and run:

kubectl apply -f hello-service-external-secret.yml

Wait a few minutes and verify that the associated Secret has been created:

kubectl get secret hello-service -o=yaml

The Secret created by the controller should look like:

apiVersion: v1
kind: Secret
metadata:
  name: hello-service
  annotations:
    cat: cheese
  labels:
    dog: farfel
type: Opaque
data:
  password: MTIzNA==

Create secrets of other types than opaque

You can override ExternalSecret type using template, for example:

apiVersion: kubernetes-client.io/v1
kind: ExternalSecret
metadata:
  name: hello-docker
spec:
  backendType: systemManager
  template:
    type: kubernetes.io/dockerconfigjson
  data:
    - key: /hello-service/hello-docker
      name: .dockerconfigjson

Templating

Kubernetes External Secrets supports templating in ExternalSecret using lodash.template.

Template is applied to all ExternalSecret.template sections of the manifest. Data retrieved from secure backend is available via the data variable. Additonal object yaml of instance of js-yaml is available in lodash templates. It can be leveraged for easier YAML content manipulation.

Templating can be used for:

  • Generating K8S Secret keys:
    • upserting plain text via ExternalSecret.template.stringData
    • upserting base64 encoded content ExternalSecret.template.data
  • For creating dynamic labels, annotations and other fields available in K8S Secret object.

To demonstrate templating functionality let's assume the secure backend, e.g. Hashicorp Vault, contains the following data

kv/extsec/secret1 kv/extsec/secret2
{
  "intKey": 11,
  "objKey": {
    "strKey": "hello world"
  }
}
{
  "arrKey": [1, 2, 3]
}

Then, one could create the following ExternalSecret

apiVersion: kubernetes-client.io/v1
kind: ExternalSecret
metadata:
  name: tmpl-ext-sec
spec:
  backendType: vault
  data:
    - key: kv/data/extsec/secret1
      name: s1
    - key: kv/data/extsec/secret2
      name: s2
  kvVersion: 2
  template:
    data:
      file.txt: |
        <%= Buffer.from(JSON.stringify(JSON.parse(data.s1).objKey)).toString("base64") %>
    metadata:
      labels:
        label1: <%= JSON.parse(data.s1).intKey %>
        label2: <%= JSON.parse(data.s1).objKey.strKey.replace(" ", "-") %>
    stringData:
      file.yaml: |
        <%= yaml.dump(JSON.parse(data.s1)) %>
        <% let s2 = JSON.parse(data.s2) %><% s2.arrKey.forEach((e, i) => { %>arr_<%= i %>: <%= e %>
        <% }) %>`
  vaultMountPoint: kubernetes
  vaultRole: demo

After applying this ExternalSecret to the K8S cluster, the operator will generate following Secret

apiVersion: v1
data:
  file.txt: eyJzdHJLZXkiOiJoZWxsbyB3b3JsZCJ9
  file.yaml: aW50S2V5OiAxMQpvYmpLZXk6CiAgc3RyS2V5OiBoZWxsbyB3b3JsZAoKYXJyXzA6IDEKYXJyXzE6IDIKYXJyXzI6IDMKYAo=
  s1: eyJpbnRLZXkiOjExLCJvYmpLZXkiOnsic3RyS2V5IjoiaGVsbG8gd29ybGQifX0=
  s2: eyJhcnJLZXkiOlsxLDIsM119
kind: Secret
metadata:
  name: tmpl-ext-sec
  labels:
    label1: "11"
    label2: hello-world
type: Opaque

Resulting Secret could be inspected to see that result is generated by lodash templating engine

$ kubectl get secret/tmpl-ext-sec -ogo-template='{{ index .data "s1" | base64decode }}'
{"intKey":11,"objKey":{"strKey":"hello world"}}

$ kubectl get secret/tmpl-ext-sec -ogo-template='{{ index .data "s2" | base64decode }}'
{"arrKey":[1,2,3]}

$ kubectl get secret/tmpl-ext-sec -ogo-template='{{ index .data "file.txt" | base64decode }}'
{"strKey":"hello world"}

$ kubectl get secret/tmpl-ext-sec -ogo-template='{{ index .data "file.yaml" | base64decode }}'
intKey: 11
objKey:
  strKey: hello world

arr_0: 1
arr_1: 2
arr_2: 3

$ kubectl get secret/tmpl-ext-sec -ogo-template='{{ .metadata.labels }}'
map[label1:11 label2:hello-world]

Scoping access

Using Namespace annotation

Enforcing naming conventions for backend keys could be done by using namespace annotations. By default an ExternalSecret may access arbitrary keys from the backend e.g.

data:
  - key: /dev/cluster1/core-namespace/hello-service/password
    name: password

An enforced naming convention helps to keep the structure tidy and limits the access according to your naming schema.

Configure the schema as a regular expression in the namespace using an annotation. This allows ExternalSecrets in core-namespace only access to secrets that start with /dev/cluster1/core-namespace/:

kind: Namespace
metadata:
  name: core-namespace
  annotations:
    # annotation key is configurable
    externalsecrets.kubernetes-client.io/permitted-key-name: "/dev/cluster1/core-namespace/.*"

Using ExternalSecret controller config

ExternalSecret config allows scoping the access of kubernetes-external-secrets controller. This allows deployment of multiple kubernetes-external-secrets instances in the same cluster and each instance can access a set of predefined namespaces.

To enable this option, set the env var in the controller side to a list of namespaces:

env:
  WATCHED_NAMESPACES: "default,qa,dev"

Using ExternalSecret config

ExternalSecret manifest allows scoping the access of kubernetes-external-secrets controller. This allows deployment of multiple kubernetes-external-secrets instances at the same cluster and each instance can access a set of ExternalSecrets.

To enable this option, set the env var in the controller side:

env:
  INSTANCE_ID: "dev-team-instance"

And in ExternalSecret side:

apiVersion: kubernetes-client.io/v1
kind: ExternalSecret
metadata:
  name: foo
spec:
  controllerId: 'dev-team-instance'
[...]

Please note

Scoping access by ExternalSecret config provides only a logical separation and it doesn't cover the security aspects. i.e it assumes that the security side is managed by another component like Kubernetes Network policies or Open Policy Agent.

Deprecations

A few properties have changed name overtime, we still maintain backwards compatbility with these but they will eventually be removed, and they are not validated using the CRD validation.

Old New
secretDescriptor spec
spec.type spec.template.type
spec.properties spec.data
backendType: secretManager backendType: secretsManager

Backends

kubernetes-external-secrets supports AWS Secrets Manager, AWS System Manager, Akeyless, Hashicorp Vault, Azure Key Vault, Google Secret Manager and Alibaba Cloud KMS Secret Manager.

AWS Secrets Manager

kubernetes-external-secrets supports both JSON objects ("Secret key/value" in the AWS console) or strings ("Plaintext" in the AWS console). Using JSON objects is useful when you need to atomically update multiple values. For example, when rotating a client certificate and private key.

When writing an ExternalSecret for a JSON object you must specify the properties to use. For example, if we add our hello-service credentials as a single JSON object:

aws secretsmanager create-secret --region us-west-2 --name hello-service/credentials --secret-string '{"username":"admin","password":"1234"}'

We can declare which properties we want from hello-service/credentials:

apiVersion: kubernetes-client.io/v1
kind: ExternalSecret
metadata:
  name: hello-service
spec:
  backendType: secretsManager
  # optional: specify role to assume when retrieving the data
  roleArn: arn:aws:iam::123456789012:role/test-role
  # optional: specify region
  region: us-east-1
  data:
    - key: hello-service/credentials
      name: password
      property: password
    - key: hello-service/credentials
      name: username
      property: username
    - key: hello-service/credentials
      name: password_previous
      # Version Stage in Secrets Manager
      versionStage: AWSPREVIOUS
      property: password
    - key: hello-service/credentials
      name: password_versioned
      # Version ID in Secrets Manager
      versionId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
      property: password

alternatively you can use dataFrom and get all the values from hello-service/credentials:

apiVersion: kubernetes-client.io/v1
kind: ExternalSecret
metadata:
  name: hello-service
spec:
  backendType: secretsManager
  # optional: specify role to assume when retrieving the data
  roleArn: arn:aws:iam::123456789012:role/test-role
  # optional: specify region
  region: us-east-1
  dataFrom:
    - hello-service/credentials

dataFrom by default retrieves the latest (AWSCURRENT) version of the backend secret, if you want to get values in bulk of a specific version, you can use dataFromWithOptions:

apiVersion: kubernetes-client.io/v1
kind: ExternalSecret
metadata:
  name: hello-service
spec:
  backendType: secretsManager
  # optional: specify role to assume when retrieving the data
  roleArn: arn:aws:iam::123456789012:role/test-role
  # optional: specify region
  region: us-east-1
  dataFromWithOptions:
    - key: hello-service/credentials
      versionStage: AWSPREVIOUS
    - key: hello-service/credentials
      versionId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

data, dataFrom and dataFromWithOptions can of course be combined, any naming conflicts will use the last defined.
In the below example data takes precedence over dataFromWithOptions and dataFrom.

apiVersion: kubernetes-client.io/v1
kind: ExternalSecret
metadata:
  name: hello-service
spec:
  backendType: secretsManager
  # optional: specify role to assume when retrieving the data
  roleArn: arn:aws:iam::123456789012:role/test-role
  # optional: specify region
  region: us-east-1
  dataFrom:
    - hello-service/credentials
  dataFromWithOptions:
    - key: hello-service/credentials
      versionId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  data:
    - key: hello-service/migration-credentials
      name: password
      property: password

AWS SSM Parameter Store

You can scrape values from SSM Parameter Store individually or by providing a path to fetch all keys inside.

When fetching all keys by path, you can also recursively scrape all the sub paths (child paths) if you need to. The default is not to scrape child paths.

apiVersion: kubernetes-client.io/v1
kind: ExternalSecret
metadata:
  name: hello-service
spec:
  backendType: systemManager
  # optional: specify role to assume when retrieving the data
  roleArn: arn:aws:iam::123456789012:role/test-role
  # optional: specify region
  region: us-east-1
  data:
    - key: /foo/name
      name: fooName
    - path: /extra-people/
      recursive: false

data and dataFrom retrieve the latest version of the parameter by default. If you want to get values for a specific version, you can append the version number to the key:

apiVersion: kubernetes-client.io/v1
kind: ExternalSecret
metadata:
  name: hello-service
spec:
  backendType: systemManager
  # optional: specify role to assume when retrieving the data
  roleArn: arn:aws:iam::123456789012:role/test-role
  # optional: specify region
  region: us-east-1
  dataFrom:
    - hello-service/credentials:3
  data:
    - key: /foo/name
      name: fooName:5

上一篇:
alexellis/arkade: Open Source Marketplace For Kubernetes发布时间:2022-07-09
下一篇:
dmfilipenko/timezones.json: Full list of timezones发布时间:2022-07-08
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap