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

Commit 72920e4

Browse files
authored
feat(aws): add support for setting an intermediate iam role (#454)
* feat(aws): add support for setting an intermediate iam role * chore: update charts readme, add some missing
1 parent 9e4d5aa commit 72920e4

File tree

7 files changed

+31
-42
lines changed

7 files changed

+31
-42
lines changed

charts/kubernetes-external-secrets/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ The following table lists the configurable parameters of the `kubernetes-externa
7474
| `crds.create` | For Helm V2 installations of the chart to install the CRD, for V3 installations use `--skip-crds` appropriately | `false` |
7575
| `customResourceManagerDisabled` | Disables the custom resource manager, requiring the CRD be installed via the chart or other means | `false` |
7676
| `env.AWS_REGION` | Set AWS_REGION in Deployment Pod | `us-west-2` |
77+
| `env.AWS_INTERMEDIATE_ROLE_ARN` | Specifies a role to be assumed before assuming role arn specified in external secrets | |
7778
| `env.LOG_LEVEL` | Set the application log level | `info` |
79+
| `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` |
80+
| `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` |
7881
| `env.METRICS_PORT` | Specify the port for the prometheus metrics server | `3001` |
7982
| `env.ROLE_PERMITTED_ANNOTATION` | Specify the annotation key where to lookup the role arn permission boundaries | `iam.amazonaws.com/permitted` |
8083
| `env.POLLER_INTERVAL_MILLISECONDS` | Set POLLER_INTERVAL_MILLISECONDS in Deployment Pod | `10000` |

charts/kubernetes-external-secrets/values.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ env:
2121
# USE_HUMAN_READABLE_LOG_LEVELS: true
2222
METRICS_PORT: 3001
2323
VAULT_ADDR: http://127.0.0.1:8200
24-
# GOOGLE_APPLICATION_CREDENTIALS: /app/gcp-creds/gcp-creds.json
24+
# Set a role to be used when assuming roles specified in external secret (AWS only)
25+
# AWS_INTERMEDIATE_ROLE_ARN:
26+
# GOOGLE_APPLICATION_CREDENTIALS: /app/gcp-creds/gcp-creds.json
2527

2628
# Create environment variables from existing k8s secrets
2729
# envVarsFromSecret:

config/aws-config.js

+13-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const merge = require('lodash.merge')
77

88
const localstack = process.env.LOCALSTACK || 0
99

10+
const intermediateRole = process.env.AWS_INTERMEDIATE_ROLE_ARN || 0
11+
1012
let secretsManagerConfig = {}
1113
let systemManagerConfig = {}
1214
let stsConfig = {
@@ -29,6 +31,13 @@ if (localstack) {
2931
}
3032
}
3133

34+
const intermediateCredentials = intermediateRole ? new AWS.ChainableTemporaryCredentials({
35+
params: {
36+
RoleArn: intermediateRole
37+
},
38+
stsConfig
39+
}) : null
40+
3241
module.exports = {
3342
secretsManagerFactory: (opts = {}) => {
3443
if (localstack) {
@@ -43,15 +52,10 @@ module.exports = {
4352
return new AWS.SSM(opts)
4453
},
4554
assumeRole: (assumeRoleOpts) => {
46-
const sts = new AWS.STS(stsConfig)
47-
48-
return new Promise((resolve, reject) => {
49-
sts.assumeRole(assumeRoleOpts, (err, res) => {
50-
if (err) {
51-
return reject(err)
52-
}
53-
resolve(res)
54-
})
55+
return new AWS.ChainableTemporaryCredentials({
56+
params: assumeRoleOpts,
57+
masterCredentials: intermediateCredentials,
58+
stsConfig
5559
})
5660
}
5761
}

lib/backends/secrets-manager-backend.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,12 @@ class SecretsManagerBackend extends KVBackend {
3131

3232
let client = this._client
3333
if (roleArn) {
34-
const res = await this._assumeRole({
34+
const credentials = this._assumeRole({
3535
RoleArn: roleArn,
3636
RoleSessionName: 'k8s-external-secrets'
3737
})
3838
client = this._clientFactory({
39-
accessKeyId: res.Credentials.AccessKeyId,
40-
secretAccessKey: res.Credentials.SecretAccessKey,
41-
sessionToken: res.Credentials.SessionToken
39+
credentials
4240
})
4341
}
4442

lib/backends/secrets-manager-backend.test.js

+4-12
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,15 @@ describe('SecretsManagerBackend', () => {
1616
const keyOptions = {}
1717

1818
const assumeRoleCredentials = {
19-
Credentials: {
20-
AccessKeyId: '1234',
21-
SecretAccessKey: '3123123',
22-
SessionToken: 'asdasdasdad'
23-
}
19+
fakeObject: 'Fake mock object'
2420
}
2521

2622
beforeEach(() => {
2723
clientMock = sinon.mock()
2824
loggerMock = sinon.mock()
2925
loggerMock.info = sinon.stub()
3026
clientFactoryMock = sinon.fake.returns(clientMock)
31-
assumeRoleMock = sinon.fake.returns(Promise.resolve(assumeRoleCredentials))
27+
assumeRoleMock = sinon.fake.returns(assumeRoleCredentials)
3228
secretsManagerBackend = new SecretsManagerBackend({
3329
clientFactory: clientFactoryMock,
3430
assumeRole: assumeRoleMock,
@@ -97,19 +93,15 @@ describe('SecretsManagerBackend', () => {
9793
})
9894

9995
expect(clientFactoryMock.lastArg).deep.equals({
100-
accessKeyId: assumeRoleCredentials.Credentials.AccessKeyId,
101-
secretAccessKey: assumeRoleCredentials.Credentials.SecretAccessKey,
102-
sessionToken: assumeRoleCredentials.Credentials.SessionToken
96+
credentials: assumeRoleCredentials
10397
})
10498
expect(clientMock.getSecretValue.calledWith({
10599
SecretId: 'fakeSecretKey',
106100
VersionStage: 'AWSCURRENT'
107101
})).to.equal(true)
108102
expect(clientFactoryMock.getCall(0).args).deep.equals([])
109103
expect(clientFactoryMock.getCall(1).args).deep.equals([{
110-
accessKeyId: assumeRoleCredentials.Credentials.AccessKeyId,
111-
secretAccessKey: assumeRoleCredentials.Credentials.SecretAccessKey,
112-
sessionToken: assumeRoleCredentials.Credentials.SessionToken
104+
credentials: assumeRoleCredentials
113105
}])
114106
expect(assumeRoleMock.callCount).equals(1)
115107
expect(secretPropertyValue).equals('fakeAssumeRoleSecretValue')

lib/backends/system-manager-backend.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,12 @@ class SystemManagerBackend extends KVBackend {
2929

3030
let client = this._client
3131
if (roleArn) {
32-
const res = await this._assumeRole({
32+
const credentials = this._assumeRole({
3333
RoleArn: roleArn,
3434
RoleSessionName: 'k8s-external-secrets'
3535
})
3636
client = this._clientFactory({
37-
accessKeyId: res.Credentials.AccessKeyId,
38-
secretAccessKey: res.Credentials.SecretAccessKey,
39-
sessionToken: res.Credentials.SessionToken
37+
credentials
4038
})
4139
}
4240
try {

lib/backends/system-manager-backend.test.js

+4-12
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,15 @@ describe('SystemManagerBackend', () => {
1515
const specOptions = {}
1616

1717
const assumeRoleCredentials = {
18-
Credentials: {
19-
AccessKeyId: '1234',
20-
SecretAccessKey: '3123123',
21-
SessionToken: 'asdasdasdad'
22-
}
18+
fakeObject: 'Fake mock object'
2319
}
2420

2521
beforeEach(() => {
2622
clientMock = sinon.mock()
2723
loggerMock = sinon.mock()
2824
loggerMock.info = sinon.stub()
2925
clientFactoryMock = sinon.fake.returns(clientMock)
30-
assumeRoleMock = sinon.fake.returns(Promise.resolve(assumeRoleCredentials))
26+
assumeRoleMock = sinon.fake.returns(assumeRoleCredentials)
3127

3228
systemManagerBackend = new SystemManagerBackend({
3329
client: clientMock,
@@ -79,19 +75,15 @@ describe('SystemManagerBackend', () => {
7975
specOptions: { roleArn: 'my-role' }
8076
})
8177
expect(clientFactoryMock.lastArg).deep.equals({
82-
accessKeyId: assumeRoleCredentials.Credentials.AccessKeyId,
83-
secretAccessKey: assumeRoleCredentials.Credentials.SecretAccessKey,
84-
sessionToken: assumeRoleCredentials.Credentials.SessionToken
78+
credentials: assumeRoleCredentials
8579
})
8680
expect(clientMock.getParameter.calledWith({
8781
Name: 'fakeSecretKey',
8882
WithDecryption: true
8983
})).to.equal(true)
9084
expect(clientFactoryMock.getCall(0).args).deep.equals([])
9185
expect(clientFactoryMock.getCall(1).args).deep.equals([{
92-
accessKeyId: assumeRoleCredentials.Credentials.AccessKeyId,
93-
secretAccessKey: assumeRoleCredentials.Credentials.SecretAccessKey,
94-
sessionToken: assumeRoleCredentials.Credentials.SessionToken
86+
credentials: assumeRoleCredentials
9587
}])
9688
expect(secretPropertyValue).equals('fakeAssumeRoleSecretValue')
9789
})

0 commit comments

Comments
 (0)