Skip to content
This repository has been archived by the owner on Jul 26, 2022. It is now read-only.

Commit

Permalink
feat(aws): add support for setting an intermediate iam role (#454)
Browse files Browse the repository at this point in the history
* feat(aws): add support for setting an intermediate iam role

* chore: update charts readme, add some missing
  • Loading branch information
Flydiverny authored Oct 4, 2020
1 parent 9e4d5aa commit 72920e4
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 42 deletions.
3 changes: 3 additions & 0 deletions charts/kubernetes-external-secrets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ The following table lists the configurable parameters of the `kubernetes-externa
| `crds.create` | For Helm V2 installations of the chart to install the CRD, for V3 installations use `--skip-crds` appropriately | `false` |
| `customResourceManagerDisabled` | Disables the custom resource manager, requiring the CRD be installed via the chart or other means | `false` |
| `env.AWS_REGION` | Set AWS_REGION in Deployment Pod | `us-west-2` |
| `env.AWS_INTERMEDIATE_ROLE_ARN` | Specifies a role to be assumed before assuming role arn specified in external secrets | |
| `env.LOG_LEVEL` | Set the application log level | `info` |
| `env.LOG_MESSAGE_KEY` | Set the key for log messages log text, for example when running on GCP it might be nice to set to `message` | `msg` |
| `env.USE_HUMAN_READABLE_LOG_LEVELS` | Sets log levels as string instead of ints eg `info` instead of `30`, setting this to any value will switch | `nil` |
| `env.METRICS_PORT` | Specify the port for the prometheus metrics server | `3001` |
| `env.ROLE_PERMITTED_ANNOTATION` | Specify the annotation key where to lookup the role arn permission boundaries | `iam.amazonaws.com/permitted` |
| `env.POLLER_INTERVAL_MILLISECONDS` | Set POLLER_INTERVAL_MILLISECONDS in Deployment Pod | `10000` |
Expand Down
4 changes: 3 additions & 1 deletion charts/kubernetes-external-secrets/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ env:
# USE_HUMAN_READABLE_LOG_LEVELS: true
METRICS_PORT: 3001
VAULT_ADDR: http://127.0.0.1:8200
# GOOGLE_APPLICATION_CREDENTIALS: /app/gcp-creds/gcp-creds.json
# Set a role to be used when assuming roles specified in external secret (AWS only)
# AWS_INTERMEDIATE_ROLE_ARN:
# GOOGLE_APPLICATION_CREDENTIALS: /app/gcp-creds/gcp-creds.json

# Create environment variables from existing k8s secrets
# envVarsFromSecret:
Expand Down
22 changes: 13 additions & 9 deletions config/aws-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const merge = require('lodash.merge')

const localstack = process.env.LOCALSTACK || 0

const intermediateRole = process.env.AWS_INTERMEDIATE_ROLE_ARN || 0

let secretsManagerConfig = {}
let systemManagerConfig = {}
let stsConfig = {
Expand All @@ -29,6 +31,13 @@ if (localstack) {
}
}

const intermediateCredentials = intermediateRole ? new AWS.ChainableTemporaryCredentials({
params: {
RoleArn: intermediateRole
},
stsConfig
}) : null

module.exports = {
secretsManagerFactory: (opts = {}) => {
if (localstack) {
Expand All @@ -43,15 +52,10 @@ module.exports = {
return new AWS.SSM(opts)
},
assumeRole: (assumeRoleOpts) => {
const sts = new AWS.STS(stsConfig)

return new Promise((resolve, reject) => {
sts.assumeRole(assumeRoleOpts, (err, res) => {
if (err) {
return reject(err)
}
resolve(res)
})
return new AWS.ChainableTemporaryCredentials({
params: assumeRoleOpts,
masterCredentials: intermediateCredentials,
stsConfig
})
}
}
6 changes: 2 additions & 4 deletions lib/backends/secrets-manager-backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,12 @@ class SecretsManagerBackend extends KVBackend {

let client = this._client
if (roleArn) {
const res = await this._assumeRole({
const credentials = this._assumeRole({
RoleArn: roleArn,
RoleSessionName: 'k8s-external-secrets'
})
client = this._clientFactory({
accessKeyId: res.Credentials.AccessKeyId,
secretAccessKey: res.Credentials.SecretAccessKey,
sessionToken: res.Credentials.SessionToken
credentials
})
}

Expand Down
16 changes: 4 additions & 12 deletions lib/backends/secrets-manager-backend.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,15 @@ describe('SecretsManagerBackend', () => {
const keyOptions = {}

const assumeRoleCredentials = {
Credentials: {
AccessKeyId: '1234',
SecretAccessKey: '3123123',
SessionToken: 'asdasdasdad'
}
fakeObject: 'Fake mock object'
}

beforeEach(() => {
clientMock = sinon.mock()
loggerMock = sinon.mock()
loggerMock.info = sinon.stub()
clientFactoryMock = sinon.fake.returns(clientMock)
assumeRoleMock = sinon.fake.returns(Promise.resolve(assumeRoleCredentials))
assumeRoleMock = sinon.fake.returns(assumeRoleCredentials)
secretsManagerBackend = new SecretsManagerBackend({
clientFactory: clientFactoryMock,
assumeRole: assumeRoleMock,
Expand Down Expand Up @@ -97,19 +93,15 @@ describe('SecretsManagerBackend', () => {
})

expect(clientFactoryMock.lastArg).deep.equals({
accessKeyId: assumeRoleCredentials.Credentials.AccessKeyId,
secretAccessKey: assumeRoleCredentials.Credentials.SecretAccessKey,
sessionToken: assumeRoleCredentials.Credentials.SessionToken
credentials: assumeRoleCredentials
})
expect(clientMock.getSecretValue.calledWith({
SecretId: 'fakeSecretKey',
VersionStage: 'AWSCURRENT'
})).to.equal(true)
expect(clientFactoryMock.getCall(0).args).deep.equals([])
expect(clientFactoryMock.getCall(1).args).deep.equals([{
accessKeyId: assumeRoleCredentials.Credentials.AccessKeyId,
secretAccessKey: assumeRoleCredentials.Credentials.SecretAccessKey,
sessionToken: assumeRoleCredentials.Credentials.SessionToken
credentials: assumeRoleCredentials
}])
expect(assumeRoleMock.callCount).equals(1)
expect(secretPropertyValue).equals('fakeAssumeRoleSecretValue')
Expand Down
6 changes: 2 additions & 4 deletions lib/backends/system-manager-backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,12 @@ class SystemManagerBackend extends KVBackend {

let client = this._client
if (roleArn) {
const res = await this._assumeRole({
const credentials = this._assumeRole({
RoleArn: roleArn,
RoleSessionName: 'k8s-external-secrets'
})
client = this._clientFactory({
accessKeyId: res.Credentials.AccessKeyId,
secretAccessKey: res.Credentials.SecretAccessKey,
sessionToken: res.Credentials.SessionToken
credentials
})
}
try {
Expand Down
16 changes: 4 additions & 12 deletions lib/backends/system-manager-backend.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,15 @@ describe('SystemManagerBackend', () => {
const specOptions = {}

const assumeRoleCredentials = {
Credentials: {
AccessKeyId: '1234',
SecretAccessKey: '3123123',
SessionToken: 'asdasdasdad'
}
fakeObject: 'Fake mock object'
}

beforeEach(() => {
clientMock = sinon.mock()
loggerMock = sinon.mock()
loggerMock.info = sinon.stub()
clientFactoryMock = sinon.fake.returns(clientMock)
assumeRoleMock = sinon.fake.returns(Promise.resolve(assumeRoleCredentials))
assumeRoleMock = sinon.fake.returns(assumeRoleCredentials)

systemManagerBackend = new SystemManagerBackend({
client: clientMock,
Expand Down Expand Up @@ -79,19 +75,15 @@ describe('SystemManagerBackend', () => {
specOptions: { roleArn: 'my-role' }
})
expect(clientFactoryMock.lastArg).deep.equals({
accessKeyId: assumeRoleCredentials.Credentials.AccessKeyId,
secretAccessKey: assumeRoleCredentials.Credentials.SecretAccessKey,
sessionToken: assumeRoleCredentials.Credentials.SessionToken
credentials: assumeRoleCredentials
})
expect(clientMock.getParameter.calledWith({
Name: 'fakeSecretKey',
WithDecryption: true
})).to.equal(true)
expect(clientFactoryMock.getCall(0).args).deep.equals([])
expect(clientFactoryMock.getCall(1).args).deep.equals([{
accessKeyId: assumeRoleCredentials.Credentials.AccessKeyId,
secretAccessKey: assumeRoleCredentials.Credentials.SecretAccessKey,
sessionToken: assumeRoleCredentials.Credentials.SessionToken
credentials: assumeRoleCredentials
}])
expect(secretPropertyValue).equals('fakeAssumeRoleSecretValue')
})
Expand Down

0 comments on commit 72920e4

Please sign in to comment.