Skip to content

feat: add awsv4 presign and rds util #44

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Mar 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8a25cc0
feat: add awsv4 presign and rds util
windmgc Jan 29, 2023
8246da8
fix add query args
windmgc Jan 30, 2023
b1208ae
fix body content digest logic
windmgc Jan 30, 2023
dc26dae
fix rds token host port
windmgc Jan 31, 2023
0aebfd8
ensure all query args are encoded
windmgc Jan 31, 2023
e316f86
fix typo
windmgc Jan 31, 2023
5e4ca23
better handling on body content
windmgc Feb 1, 2023
d0c2d31
expire value should have valid range
windmgc Feb 1, 2023
836c796
X-Amz-Signature should be moved to the end of the request
windmgc Feb 1, 2023
0f45681
fix add request args should not decode at first
windmgc Feb 2, 2023
47ef9c0
refactor some util functions
windmgc Feb 2, 2023
09545ee
fix rockspec
windmgc Feb 2, 2023
964e83d
fix rds util annotation
windmgc Feb 2, 2023
00a791e
fix presign annotation
windmgc Feb 2, 2023
f1770e2
add rds utils spec
windmgc Feb 2, 2023
0002ef1
rename spec file
windmgc Feb 2, 2023
c6ec5f6
fix dependency
windmgc Feb 2, 2023
16a1715
add presign test
windmgc Feb 6, 2023
c4cd2a4
fix ngx time hack
windmgc Feb 20, 2023
fdd99b3
fix rockspec
windmgc Feb 20, 2023
f67e76e
fix spec
windmgc Feb 20, 2023
ba5b31a
change ngx time hack from each block to setup/teardown block
windmgc Feb 20, 2023
5aae763
chore(docs): update doc comments to render properly
Tieske Feb 28, 2023
5c6f2d2
replace intreface with more SDK like interface
Tieske Feb 28, 2023
a61c0b8
fix presign request param
windmgc Mar 1, 2023
a1c41b9
fix test
windmgc Mar 1, 2023
7f21b93
make param format more clear, avoid obfuscating between database inst…
windmgc Mar 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ clean:
-@rm *.rock
-@rm -rf delete-me
-@rm -rf src/resty/aws/raw-api
-@rm -rf ./docs; git checkout ./docs

$(target_rock):
[ -n "$$VERSION" ] || { echo VERSION not set; exit 1; }
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,16 @@ Release process:
1. upload using: `VERSION=x.y.z APIKEY=abc... make upload`
1. test installing the rock from LuaRocks

### unreleased
### 1.x.0 (unreleased)

- **IMPORTANT-IMPORTANT-IMPORTANT** feat: enable TLS name verification. This might
break if your CA store is not the default system one. See [usage notes](#usage-important).
[#47](https://github.com/Kong/lua-resty-aws/pull/47)
- fix: STS regional endpoints woudl re-inject the region on every authentication
(after a token expired), causing bad hostnames to be used
[#45](https://github.com/Kong/lua-resty-aws/issues/45)
- Feat: add RDS.Signer to generate tokens for RDS DB access
[#44](https://github.com/Kong/lua-resty-aws/issues/44)

### 1.1.2 (7-Dec-2022)

Expand Down
4 changes: 4 additions & 0 deletions lua-resty-aws-dev-1.rockspec.template
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dependencies = {
"penlight ~> 1",
"lua-resty-http >= 0.16",
"lua-resty-luasocket ~> 1",
"lua-resty-openssl >= 0.8.17",
}

build = {
Expand All @@ -38,8 +39,11 @@ build = {
["resty.aws.request.build"] = "src/resty/aws/request/build.lua",
["resty.aws.request.sign"] = "src/resty/aws/request/sign.lua",
["resty.aws.request.execute"] = "src/resty/aws/request/execute.lua",
["resty.aws.request.signatures.utils"] = "src/resty/aws/request/signatures/utils.lua",
["resty.aws.request.signatures.v4"] = "src/resty/aws/request/signatures/v4.lua",
["resty.aws.request.signatures.presign"] = "src/resty/aws/request/signatures/presign.lua",
["resty.aws.request.signatures.none"] = "src/resty/aws/request/signatures/none.lua",
["resty.aws.service.rds.signer"] = "src/resty/aws/service/rds/signer.lua",
["resty.aws.credentials.Credentials"] = "src/resty/aws/credentials/Credentials.lua",
["resty.aws.credentials.ChainableTemporaryCredentials"] = "src/resty/aws/credentials/ChainableTemporaryCredentials.lua",
["resty.aws.credentials.CredentialProviderChain"] = "src/resty/aws/credentials/CredentialProviderChain.lua",
Expand Down
82 changes: 82 additions & 0 deletions spec/02-requests/05-presign_v4_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
setmetatable(_G, nil)

-- -- hock request sending
-- package.loaded["resty.aws.request.execute"] = function(...)
-- return ...
-- end

local AWS = require("resty.aws")
local AWS_global_config = require("resty.aws.config").global

local presign = require("resty.aws.request.signatures.presign")

local config = AWS_global_config
local aws = AWS(config)


aws.config.credentials = aws:Credentials {
accessKeyId = "test_id",
secretAccessKey = "test_key",
}

aws.config.region = "test_region"

describe("Presign request", function()
local presigned_request_data

setup(function()
ngx.origin_time = ngx.time
ngx.time = function ()
return 1667543171
end
end)

teardown(function ()
ngx.time = ngx.origin_time
ngx.origin_time = nil
end)

before_each(function()
local request_data = {
method = "GET",
scheme = "https",
tls = true,
host = "test_host",
port = 443,
path = "/",
query = "Action=TestAction",
headers = {
["Host"] = "test_host:443",
},
}

presigned_request_data = presign(aws.config, request_data, "test_service", "test_region", 900)
end)

after_each(function()
presigned_request_data = nil
end)

it("should have correct signed request host header", function()
assert.same(presigned_request_data.headers["Host"], "test_host:443")
assert.same(presigned_request_data.host, "test_host")
assert.same(presigned_request_data.port, 443)
end)

it("should have correct signed request path", function ()
assert.same(presigned_request_data.path, "/")
end)

it("should have correct signed query parameters", function ()
local query_params = {}
for k, v in presigned_request_data.query:gmatch("([^&=]+)=?([^&]*)") do
query_params[ngx.unescape_uri(k)] = ngx.unescape_uri(v)
end
assert.same(query_params["X-Amz-Algorithm"], "AWS4-HMAC-SHA256")
assert.same(query_params["Action"], "TestAction")
assert.same(query_params["X-Amz-Date"], "20221104T062611Z")
assert.same(query_params["X-Amz-Expires"], "900")
assert.same(query_params["X-Amz-SignedHeaders"], "host")
assert.same(query_params["X-Amz-Credential"], "test_id/20221104/test_region/test_service/aws4_request")
end)
end)
19 changes: 13 additions & 6 deletions spec/04-services/01-secret_manager.lua
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
setmetatable(_G, nil)

-- to get a definitive result
-- luacheck:ignore
ngx.time = function()
return 1667543171
end

-- hook request sending
package.loaded["resty.aws.request.execute"] = function(...)
return ...
Expand All @@ -29,6 +23,19 @@ aws.config.region = "test_region"

describe("Secret Manager service", function()
local sm

setup(function()
ngx.origin_time = ngx.time
ngx.time = function ()
return 1667543171
end
end)

teardown(function ()
ngx.time = ngx.origin_time
ngx.origin_time = nil
end)

before_each(function()
sm = assert(aws:SecretsManager {})
end)
Expand Down
19 changes: 13 additions & 6 deletions spec/04-services/02-s3.lua
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
setmetatable(_G, nil)

-- to get a definitive result
-- luacheck:ignore
ngx.time = function()
return 1667543171
end

-- hock request sending
package.loaded["resty.aws.request.execute"] = function(...)
return ...
Expand All @@ -29,6 +23,19 @@ aws.config.region = "test_region"

describe("S3 service", function()
local s3, s3_3rd

setup(function()
ngx.origin_time = ngx.time
ngx.time = function ()
return 1667543171
end
end)

teardown(function ()
ngx.time = ngx.origin_time
ngx.origin_time = nil
end)

before_each(function()
s3 = assert(aws:S3 {})
s3_3rd = assert(aws:S3 {
Expand Down
19 changes: 13 additions & 6 deletions spec/04-services/03-s3_compat_api.lua
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
setmetatable(_G, nil)

-- to get a definitive result
-- luacheck:ignore
ngx.time = function()
return 1667543171
end

-- hock request sending
package.loaded["resty.aws.request.execute"] = function(...)
return ...
Expand All @@ -31,6 +25,19 @@ aws.config.region = "test_region"

describe("S3 service", function()
local s3, s3_3rd

setup(function()
ngx.origin_time = ngx.time
ngx.time = function ()
return 1667543171
end
end)

teardown(function ()
ngx.time = ngx.origin_time
ngx.origin_time = nil
end)

before_each(function()
s3 = assert(aws:S3 {})
s3_3rd = assert(aws:S3 {
Expand Down
73 changes: 73 additions & 0 deletions spec/04-services/04-rds-utils_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
setmetatable(_G, nil)

-- -- hock request sending
-- package.loaded["resty.aws.request.execute"] = function(...)
-- return ...
-- end

local AWS = require("resty.aws")
local AWS_global_config = require("resty.aws.config").global

local config = AWS_global_config
local aws = AWS(config)

aws.config.credentials = aws:Credentials {
accessKeyId = "test_id",
secretAccessKey = "test_key",
}

aws.config.region = "test_region"

local DB_ENDPOINT = "test_database.test_cluster.us-east-1.rds.amazonaws.com"
local DB_PORT = "443"
local DB_REGION = "us-east-1"
local DB_USER = "test_user"

describe("RDS utils", function()
local rds, signer
setup(function()
ngx.origin_time = ngx.time
ngx.time = function ()
return 1667543171
end
end)

teardown(function ()
ngx.time = ngx.origin_time
ngx.origin_time = nil
end)

before_each(function()
rds = aws:RDS()
signer = rds:Signer {
hostname = DB_ENDPOINT,
port = DB_PORT,
username = DB_USER,
region = DB_REGION, -- override aws config
}
end)

after_each(function()
rds = nil
signer = nil
end)

it("should generate expected IAM auth token with mock key", function()
local auth_token, err = signer:getAuthToken()
local expected_auth_token = "test_database.test_cluster.us-east-1.rds.amazonaws.com:443/?X-Amz-Signature=ff72d46f1937c1f5917f69d694929ca814b781619b8d730451c7ffef050059b0&Action=connect&DBUser=test_user&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=test_id%2F20221104%2Fus-east-1%2Frds-db%2Faws4_request&X-Amz-Date=20221104T062611Z&X-Amz-Expires=900&X-Amz-SignedHeaders=host"
assert.is_nil(err)
assert.same(auth_token, expected_auth_token)
end)

it("should generate expected IAM auth token with mock temporary credential", function()
signer.config.credentials = aws:Credentials {
accessKeyId = "test_id2",
secretAccessKey = "test_key2",
sessionToken = "test_token2",
}
local auth_token, err = signer:getAuthToken()
local expected_auth_token = "test_database.test_cluster.us-east-1.rds.amazonaws.com:443/?X-Amz-Signature=7fcb20a161bb493b405686590604bfb864f8ac68dea84b903cd551e93f850ac5&Action=connect&DBUser=test_user&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=test_id2%2F20221104%2Fus-east-1%2Frds-db%2Faws4_request&X-Amz-Date=20221104T062611Z&X-Amz-Expires=900&X-Amz-Security-Token=test_token2&X-Amz-SignedHeaders=host"
assert.is_nil(err)
assert.same(auth_token, expected_auth_token)
end)
end)
2 changes: 2 additions & 0 deletions src/resty/aws/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,8 @@ function AWS:new(config)
aws = aws_instance,
config = service_config,
api = api,
-- Add service specific methods:
Signer = (service_id == "RDS") and require("resty.aws.service.rds.signer") or nil
}

AWS.configureEndpoint(service_instance)
Expand Down
Loading