Skip to content

Commit

Permalink
Secrets config (#535)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssoroka authored Oct 28, 2021
1 parent a6eb85f commit 63e9c87
Show file tree
Hide file tree
Showing 26 changed files with 1,588 additions and 213 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ docker-desktop.yaml

# dir created by some versions of openapi-generator
.openapi-generator
secrets/foo/bar:secret
secrets/foo2/bar
secrets/foo2/bar2
secrets/foo3/bar:secret
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ See [Okta](./docs/sources/okta.md) for detailed Okta configuration steps.

Cluster name is auto-discovered or can be set statically in Helm with `engine.name`.

Also see [secrets.md](./docs/secrets.md) for details on how secrets work.

```yaml
# example values.yaml
---
Expand All @@ -51,9 +53,9 @@ config:
- kind: okta
domain: <Okta domain>
client-id: <Okta client ID>
client-secret: <Okta client secret>
client-secret: <secret kind>:<Okta client secret name>
okta:
api-token: <Okta API token>
api-token: <secret kind>:<Okta API token name>
groups:
- name: Everyone
roles:
Expand Down
4 changes: 2 additions & 2 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ sources:
- kind: okta
domain: acme.okta.com
client-id: 0oapn0qwiQPiMIyR35d6
client-secret: infra-okta/clientSecret
client-secret: kubernetes:infra-okta/clientSecret
okta:
api-token: infra-okta/apiToken
api-token: kubernetes:infra-okta/apiToken

groups:
- name: administrators
Expand Down
174 changes: 174 additions & 0 deletions docs/secrets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# Secrets

Infra supports many secret storage backends, including, but not limited to:

- Kubernetes
- Vault
- AWS Secrets Manager
- AWS SSM (Systems Manager Parameter Store)
- Environment variables
- Files on the file system
- plaintext secrets (though probably not recommended)

## Usage

These can be referenced in the Infra config file using the scheme `<secret-backend>:<secret-key>`

Examples follow.

### Kubernetes

```yaml
clientSecret: kubernetes:infra-okta/clientSecret
```
This would read the `infra-okta/clientSecret` key from a Kubernetes secret.

Kubernetes takes configuration, like so:

```yaml
secrets:
- name: kubernetes # can optionally provide a custom name
kind: kubernetes
namespace: mynamespace
```

### Vault

```yaml
clientSecret: vault:infra-okta-clientSecret
```

This would read the `infra-okta-clientSecret` secret from Vault

Vault takes configuration, like so:

```yaml
secrets:
- name: vault # can optionally provide a custom name
kind: vault
transitMount: /transit
secretMount: /secret
token: env:VAULT_TOKEN # secret config can even reference other built-in secret types, like env
namespace: mynamespace
address: https://vault
```

### AWS Secrets Manager

```yaml
clientSecret: awssm:infra-okta-clientSecret
```

Secrets Manager takes configuration, like so:

```yaml
secrets:
- name: awssm # can optionally provide a custom name
kind: awssm
endpoint: https://kms.endpoint
region: us-west-2
accessKeyId: env:AWS_ACCESS_KEY_ID # secret config can even reference other built-in secret types, like env
secretAccessKey: env:AWS_SECRET_ACCESS_KEY
```

### AWS SSM (Systems Manager Parameter Store)

```yaml
clientSecret: awsssm:infra-okta-clientSecret
```

SSM takes configuration, like so:

```yaml
secrets:
- name: awsssm # can optionally provide a custom name
kind: awsssm
keyId: 1234abcd-12ab-34cd-56ef-1234567890ab # optional, if set it's the KMS key that should be used for decryption
endpoint: https://kms.endpoint
region: us-west-2
accessKeyId: env:AWS_ACCESS_KEY_ID # secret config can even reference other built-in secret types, like env
secretAccessKey: env:AWS_SECRET_ACCESS_KEY
```

### Environment variables

```yaml
clientSecret: env:OKTA_CLIENT_SECRET
```

env is built-in and does not need to be declared, but if you do want to declare the configuration for it, you could use this to create a custom env handler, like so:

```yaml
secrets:
- name: base64env
kind: env
base64: true
base64UrlEncoded: false
base64Raw: false
```

which you would then use like:

```bash
$ export OKTA_CLIENT_SECRET="c3VwZXIgc2VjcmV0IQ=="
```

```yaml
clientSecret: base64env:OKTA_CLIENT_SECRET
```

### Files on the file system

It's a common pattern to write secrets to a file on disk and then have an app read them.

```yaml
clientSecret: file:/var/secrets/okta-client-secret.txt
```

file is built-in and does not need to be declared, but if you do want to declare the configuration for it, you could use this to create a custom handler, like so:

```yaml
secrets:
- name: base64file
kind: file
base64: true
base64UrlEncoded: false
base64Raw: false
path: /var/secrets # optional: assume all files mentioned are in this root directory
```

which you would then use like:

```bash
$ echo "c3VwZXIgc2VjcmV0IQ==" > /var/secrets/okta-client-secret.txt
```

```yaml
clientSecret: base64file:okta-client-secret.txt
```

### plaintext secrets (though probably not recommended)

Sometimes it can be handy to support plain text secrets right in the yaml config, especially when the yaml is being generated and the secrets are coming from elsewhere.

```yaml
clientSecret: plaintext:mySupErSecrEt
```

plain is built-in and does not need to be declared, but if you do want to declare the configuration for it, you could use this to create a custom handler, like so:

```yaml
secrets:
- name: base64text
kind: plain
base64: true
base64UrlEncoded: false
base64Raw: false
```

which you would then use like:

```yaml
clientSecret: base64text:bXlTdXBFclNlY3JFdA==
```
18 changes: 12 additions & 6 deletions docs/sources/okta.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ sources:
- kind: okta
domain: acme.okta.com
client-id: 0oapn0qwiQPiMIyR35d6
client-secret: infra-okta/clientSecret
client-secret: kubernetes:infra-okta/clientSecret
okta:
api-token: infra-okta/apiToken
api-token: kubernetes:infra-okta/apiToken
```

## Create an Okta App
Expand All @@ -47,18 +47,24 @@ sources:
![okta_api_token](https://user-images.githubusercontent.com/5853428/124652864-787b5d00-de51-11eb-81d8-e503babfdbca.png)

### Add Okta secrets to the Infra deployment

The Okta client secret and API token are sensitive information which cannot be stored in the Infra configuration file. In order for Infra to access these secret values they must be stored in Kubernetes Secret objects **in the same namespace that the Infra is deployed in**.

Create [Kubernetes Secret objects](https://kubernetes.io/docs/tasks/configmap-secret/) to store the Okta client secret and API token (noted in steps 4 and 5 of `Create an Okta App` respectively). You can name these Secrets as you desire, these names will be specified in the Infra configuration.

#### Example Secret Creation

There are [many ways to store secrets](../secrets.md). Here's an example of using Kubernetes for the secret storage.

Store the Okta client secret and API token on the same Kubernetes Secret object in the namespace that Infra is running in.
```
OKTA_CLIENT_SECRET=jfpn0qwiQPiMIfs408fjs048fjpn0qwiQPiMajsdf08j10j2
OKTA_API_TOKEN=001XJv9xhv899sdfns938haos3h8oahsdaohd2o8hdao82hd
kubectl -n infrahq create secret generic infra-okta --from-literal=clientSecret=$OKTA_CLIENT_SECRET --from-literal=apiToken=$OKTA_API_TOKEN
```

see [secrets.md](../secrets.md) for further details.

## Add Okta Information to Infra Configuration

Edit your [Infra configuration](./configuration.md) (e.g. `infra.yaml`) to include an Okta source:
Expand All @@ -70,9 +76,9 @@ sources:
- kind: okta
domain: example.okta.com
client-id: 0oapn0qwiQPiMIyR35d6
client-secret: infra-okta/clientSecret # <Kubernetes secret object>/<secret name>
client-secret: kubernetes:infra-okta/clientSecret # <secret kind>:<secret name>
okta:
api-token: infra-okta/apiToken
api-token: kubernetes:infra-okta/apiToken
```
Then apply this config change:
Expand All @@ -91,9 +97,9 @@ config:
- kind: okta
domain: example.okta.com
client-id: 0oapn0qwiQPiMIyR35d6
client-secret: infra-okta/clientSecret # <Kubernetes secret object>/<secret name>
client-secret: kubernetes:infra-okta/clientSecret # <secret kind>:<secret name>
okta:
api-token: infra-okta/apiToken
api-token: kubernetes:infra-okta/apiToken
```
Then apply this config change:
Expand Down
10 changes: 0 additions & 10 deletions internal/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -691,13 +691,3 @@ func (k *Kubernetes) Endpoint() (string, error) {

return fmt.Sprintf("%s:%d", host, port.Port), nil
}

// GetSecret returns a K8s secret object with the specified name from the current namespace if it exists
func (k *Kubernetes) GetSecret(secret string) (string, error) {
b, err := k.SecretReader.GetSecret(secret)
if b == nil {
return "", err
}

return string(b), err
}
41 changes: 0 additions & 41 deletions internal/kubernetes/kubernetes_test.go

This file was deleted.

17 changes: 11 additions & 6 deletions internal/registry/_testdata/infra.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
secrets:
- name: base64
kind: plaintext
base64: true

sources:
- kind: okta
domain: overwrite.example.com
client-id: 0oapn0qwiQPiMIyR35d6
client-secret: okta-secrets/clientSecret
client-id: base64:MG9hcG4wcXdpUVBpTUl5UjM1ZDY=
client-secret: kubernetes:okta-secrets/clientSecret
okta:
api-token: okta-secrets/apiToken
api-token: kubernetes:okta-secrets/apiToken
- kind: okta
domain: https://test.example.com
client-id: 0oapn0qwiQPiMIyR35d6
client-secret: okta-secrets/clientSecret
client-id: plaintext:0oapn0qwiQPiMIyR35d6
client-secret: kubernetes:okta-secrets/clientSecret
okta:
api-token: okta-secrets/apiToken
api-token: kubernetes:okta-secrets/apiToken

groups:
- name: ios-developers
Expand Down
Loading

0 comments on commit 63e9c87

Please sign in to comment.