Skip to content

Commit f6a4468

Browse files
authored
feat: container credential provider support auth token (#107)
1 parent 1d4f676 commit f6a4468

File tree

4 files changed

+106
-1
lines changed

4 files changed

+106
-1
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ Release process:
185185
- security: remove the documentation entry that contains a sample access key from AWS SDK. This
186186
avoids false postive vulnerability report.
187187
[102](https://github.com/Kong/lua-resty-aws/pull/102)
188+
- feat: container credential provider now supports using auth token defined in
189+
AWS_CONTAINER_AUTHORIZATION_TOKEN and AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE.
190+
[107](https://github.com/Kong/lua-resty-aws/pull/107)
188191

189192
### 1.3.6 (25-Dec-2023)
190193

spec/03-credentials/04-RemoteCredentials_spec.lua

+69
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ local restore = require "spec.helpers"
44

55
-- Mock for HTTP client
66
local response = {} -- override in tests
7+
local http_records = {} -- record requests for assertions
78
local http = {
89
new = function()
910
return {
@@ -12,8 +13,10 @@ local http = {
1213
set_timeouts = function() return true end,
1314
request = function(self, opts)
1415
if opts.path == "/test/path" then
16+
table.insert(http_records, opts)
1517
return { -- the response for the credentials
1618
status = (response or {}).status or 200,
19+
headers = opts and opts.headers or {},
1720
read_body = function() return json.encode {
1821
AccessKeyId = (response or {}).AccessKeyId or "access",
1922
SecretAccessKey = (response or {}).SecretAccessKey or "secret",
@@ -30,6 +33,12 @@ local http = {
3033
end,
3134
}
3235

36+
local pl_utils = {
37+
readfile = function()
38+
return "testtokenabc123"
39+
end
40+
}
41+
3342

3443
describe("RemoteCredentials", function()
3544

@@ -85,3 +94,63 @@ describe("RemoteCredentials with customized full URI", function ()
8594
assert.equal("token", token)
8695
end)
8796
end)
97+
98+
describe("RemoteCredentials with full URI and token file", function ()
99+
it("fetches credentials", function ()
100+
local RemoteCredentials
101+
102+
restore()
103+
restore.setenv("AWS_CONTAINER_CREDENTIALS_FULL_URI", "http://localhost:12345/test/path")
104+
restore.setenv("AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE", "/var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token")
105+
106+
local _ = require("resty.aws.config").global -- load config before mocking http client
107+
package.loaded["resty.luasocket.http"] = http
108+
package.loaded["pl.utils"] = pl_utils
109+
110+
RemoteCredentials = require "resty.aws.credentials.RemoteCredentials"
111+
finally(function()
112+
restore()
113+
end)
114+
115+
local cred = RemoteCredentials:new()
116+
local success, key, secret, token = cred:get()
117+
assert.equal(true, success)
118+
assert.equal("access", key)
119+
assert.equal("secret", secret)
120+
assert.equal("token", token)
121+
122+
assert.not_nil(http_records[#http_records].headers)
123+
assert.equal(http_records[#http_records].headers["Authorization"], "testtokenabc123")
124+
end)
125+
end)
126+
127+
describe("RemoteCredentials with full URI and token and token file, file takes higher precedence", function ()
128+
it("fetches credentials", function ()
129+
local RemoteCredentials
130+
131+
restore()
132+
restore.setenv("AWS_CONTAINER_CREDENTIALS_FULL_URI", "http://localhost:12345/test/path")
133+
restore.setenv("AWS_CONTAINER_AUTHORIZATION_TOKEN", "testtoken")
134+
restore.setenv("AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE", "/var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token")
135+
136+
local _ = require("resty.aws.config").global -- load config before mocking http client
137+
package.loaded["resty.luasocket.http"] = http
138+
package.loaded["pl.utils"] = pl_utils
139+
140+
RemoteCredentials = require "resty.aws.credentials.RemoteCredentials"
141+
finally(function()
142+
restore()
143+
end)
144+
145+
local cred = RemoteCredentials:new()
146+
local success, key, secret, token = cred:get()
147+
assert.equal(true, success)
148+
assert.equal("access", key)
149+
assert.equal("secret", secret)
150+
assert.equal("token", token)
151+
152+
assert.not_nil(http_records[#http_records].headers)
153+
assert.equal(http_records[#http_records].headers["Authorization"], "testtokenabc123")
154+
end)
155+
end)
156+

src/resty/aws/config.lua

+9
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
-- * `AMAZON_SESSION_TOKEN`
5858
-- * `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI`
5959
-- * `AWS_CONTAINER_CREDENTIALS_FULL_URI`
60+
-- * `AWS_CONTAINER_AUTHORIZATION_TOKEN`
61+
-- * `AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE`
6062

6163

6264
local pl_path = require "pl.path"
@@ -140,6 +142,13 @@ local env_vars = {
140142
-- Variables used in RemoteCredentials (and in the CredentialProviderChain)
141143
AWS_CONTAINER_CREDENTIALS_RELATIVE_URI = { name = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", default = nil },
142144
AWS_CONTAINER_CREDENTIALS_FULL_URI = { name = "AWS_CONTAINER_CREDENTIALS_FULL_URI", default = nil },
145+
-- Token related Variables used in RemoteCredentials
146+
-- Note that AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE has higher priority than AWS_CONTAINER_AUTHORIZATION_TOKEN
147+
-- if both are set, the value in AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE will be used
148+
--
149+
-- This is also used by EKS Pod Identity authorization
150+
AWS_CONTAINER_AUTHORIZATION_TOKEN = { name = "AWS_CONTAINER_AUTHORIZATION_TOKEN", default = nil },
151+
AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE = { name = "AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE", default = nil },
143152

144153
-- HTTP/HTTPs proxy settings
145154
HTTP_PROXY = { name = "http_proxy", default = nil },

src/resty/aws/credentials/RemoteCredentials.lua

+25-1
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ local DEFAULT_SERVICE_REQUEST_TIMEOUT = 5000
1313
local url = require "socket.url"
1414
local http = require "resty.luasocket.http"
1515
local json = require "cjson"
16+
local readfile = require("pl.utils").readfile
1617

1718

1819
local FullUri
20+
local AuthToken
21+
local AuthTokenFile
1922

2023

2124
local function initialize()
@@ -31,7 +34,7 @@ local function initialize()
3134

3235
local FULL_URI_UNRESTRICTED_PROTOCOLS = makeset { "https" }
3336
local FULL_URI_ALLOWED_PROTOCOLS = makeset { "http", "https" }
34-
local FULL_URI_ALLOWED_HOSTNAMES = makeset { "localhost", "127.0.0.1" }
37+
local FULL_URI_ALLOWED_HOSTNAMES = makeset { "localhost", "127.0.0.1", "169.254.170.23" }
3538
local RELATIVE_URI_HOST = '169.254.170.2'
3639

3740
local function getFullUri()
@@ -76,6 +79,10 @@ local function initialize()
7679
({ http = 80, https = 443 })[FullUri.scheme]
7780
end
7881

82+
-- get auth token/file
83+
AuthToken = aws_config.global.AWS_CONTAINER_AUTHORIZATION_TOKEN
84+
AuthTokenFile = aws_config.global.AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE
85+
7986
initialize = nil
8087
end
8188

@@ -107,6 +114,22 @@ function RemoteCredentials:refresh()
107114
return nil, "No URI environment variables found for RemoteCredentials"
108115
end
109116

117+
118+
local headers = {}
119+
120+
if AuthToken then
121+
headers["Authorization"] = AuthToken
122+
end
123+
124+
if AuthTokenFile then
125+
local token, err = readfile(AuthTokenFile)
126+
if not token then
127+
return nil, "Failed reading AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE: " .. err
128+
end
129+
130+
headers["Authorization"] = token
131+
end
132+
110133
local client = http.new()
111134
client:set_timeout(DEFAULT_SERVICE_REQUEST_TIMEOUT)
112135

@@ -122,6 +145,7 @@ function RemoteCredentials:refresh()
122145
local response, err = client:request {
123146
method = "GET",
124147
path = FullUri.path,
148+
headers = headers,
125149
}
126150

127151
if not response then

0 commit comments

Comments
 (0)