Skip to content
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

Support IMDSv1 and IMDSv2 #9962

Merged
merged 2 commits into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions kong/plugins/aws-lambda/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ local function fetch_aws_credentials(aws_conf)
end

if aws_conf.aws_assume_role_arn then
local metadata_credentials, err = fetch_metadata_credentials()
local metadata_credentials, err = fetch_metadata_credentials(aws_conf)

if err then
return nil, err
Expand All @@ -52,7 +52,7 @@ local function fetch_aws_credentials(aws_conf)
metadata_credentials.session_token)

else
return fetch_metadata_credentials()
return fetch_metadata_credentials(aws_conf)
end
end

Expand Down Expand Up @@ -265,6 +265,7 @@ function AWSLambdaHandler:access(conf)
aws_region = conf.aws_region,
aws_assume_role_arn = conf.aws_assume_role_arn,
aws_role_session_name = conf.aws_role_session_name,
aws_imds_protocol_version = conf.aws_imds_protocol_version,
}

if not conf.aws_key then
Expand Down
58 changes: 50 additions & 8 deletions kong/plugins/aws-lambda/iam-ec2-credentials.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,71 @@ local kong = kong
local METADATA_SERVICE_PORT = 80
local METADATA_SERVICE_REQUEST_TIMEOUT = 5000
local METADATA_SERVICE_HOST = "169.254.169.254"
local METADATA_SERVICE_URI = "http://" .. METADATA_SERVICE_HOST .. ":" .. METADATA_SERVICE_PORT ..
local METADATA_SERVICE_TOKEN_URI = "http://" .. METADATA_SERVICE_HOST .. ":" .. METADATA_SERVICE_PORT ..
"/latest/api/token"
local METADATA_SERVICE_IAM_URI = "http://" .. METADATA_SERVICE_HOST .. ":" .. METADATA_SERVICE_PORT ..
"/latest/meta-data/iam/security-credentials/"


local function fetch_ec2_credentials()
local function fetch_ec2_credentials(config)
local client = http.new()
client:set_timeout(METADATA_SERVICE_REQUEST_TIMEOUT)
local role_name_request_res, err = client:request_uri(METADATA_SERVICE_URI)

local protocol_version = config.aws_imds_protocol_version
local imds_session_headers

if protocol_version == "v1" then

-- When using IMSDv1, the role is retrieved with a simple GET
-- request requiring no special headers.
imds_session_headers = {}

elseif protocol_version == "v2" then

-- When using IMSDv1, the role is retrieved with a GET request
-- that has a valid X-aws-ec2-metadata-token header with a valid
-- token, which needs to be retrieved with a PUT request.
local token_request_res, err = client:request_uri(METADATA_SERVICE_TOKEN_URI, {
method = "PUT",
headers = {
["X-aws-ec2-metadata-token-ttl-seconds"] = "60",
},
})

if not token_request_res then
return nil, "Could not fetch IMDSv2 token from metadata service: " .. tostring(err)
end

if token_request_res.status ~= 200 then
return nil, "Fetching IMDSv2 token from metadata service returned status code " ..
token_request_res.status .. " with body " .. token_request_res.body
end
imds_session_headers = { ["X-aws-ec2-metadata-token"] = token_request_res.body }

else
return nil, "Unrecognized aws_imds_protocol_version " .. tostring(protocol_version) .. " set in configuration"
end

local role_name_request_res, err = client:request_uri(METADATA_SERVICE_IAM_URI, {
headers = imds_session_headers,
})

if not role_name_request_res then
return nil, "Could not fetch role name from metadata service: " .. tostring(err)
end

if role_name_request_res.status ~= 200 then
return nil, "Fetching role name from metadata service returned status code " ..
role_name_request_res.status .. " with body " .. role_name_request_res.body
role_name_request_res.status .. " with body " .. role_name_request_res.body
end

local iam_role_name = role_name_request_res.body

kong.log.debug("Found IAM role on instance with name: ", iam_role_name)

local iam_security_token_request, err = client:request_uri(METADATA_SERVICE_URI .. iam_role_name)
local iam_security_token_request, err = client:request_uri(METADATA_SERVICE_IAM_URI .. iam_role_name, {
headers = imds_session_headers,
})

if not iam_security_token_request then
return nil, "Failed to request IAM credentials for role " .. iam_role_name ..
" Request returned error: " .. tostring(err)
Expand Down Expand Up @@ -63,9 +105,9 @@ local function fetch_ec2_credentials()
end


local function fetchCredentialsLogged()
local function fetchCredentialsLogged(config)
-- wrapper to log any errors
local creds, err, ttl = fetch_ec2_credentials()
local creds, err, ttl = fetch_ec2_credentials(config)
if creds then
return creds, err, ttl
end
Expand Down
6 changes: 6 additions & 0 deletions kong/plugins/aws-lambda/schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ return {
type = "boolean",
default = true,
} },
{ aws_imds_protocol_version = {
type = "string",
required = true,
default = "v1",
one_of = { "v1", "v2" }
} },
}
},
} },
Expand Down
30 changes: 28 additions & 2 deletions spec/03-plugins/27-aws-lambda/03-iam-ec2-credentials_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe("[AWS Lambda] iam-ec2", function()
after_each(function()
end)

it("should fetch credentials from metadata service", function()
it("should fetch credentials from metadata service using IMDSv1", function()
http_responses = {
"EC2_role",
[[
Expand All @@ -44,7 +44,33 @@ describe("[AWS Lambda] iam-ec2", function()
]]
}

local iam_role_credentials, err = fetch_ec2()
local iam_role_credentials, err = fetch_ec2({ aws_imds_protocol_version = "v1" })

assert.is_nil(err)
assert.equal("the Access Key", iam_role_credentials.access_key)
assert.equal("the Big Secret", iam_role_credentials.secret_key)
assert.equal("the Token of Appreciation", iam_role_credentials.session_token)
assert.equal(1552424170, iam_role_credentials.expiration)
end)

it("should fetch credentials from metadata service using IMDSv2", function()
http_responses = {
"SOME-TOKEN",
"EC2_role",
[[
{
"Code" : "Success",
"LastUpdated" : "2019-03-12T14:20:45Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "the Access Key",
"SecretAccessKey" : "the Big Secret",
"Token" : "the Token of Appreciation",
"Expiration" : "2019-03-12T20:56:10Z"
}
]]
}

local iam_role_credentials, err = fetch_ec2({ aws_imds_protocol_version = "v2" })

assert.is_nil(err)
assert.equal("the Access Key", iam_role_credentials.access_key)
Expand Down