ami: imdsv2 support
https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/ One has to get a token now via PUT. This is because there is a bunch of open proxies out there which blindly forwarded everything to internal network including metadata requests. They have found that PUT requests don't cleanly proxy and also AWS rejects token requests with X-Forwarded-For.
This commit is contained in:
@@ -50,7 +50,16 @@ async function providerTokenAuth(req, res, next) {
|
||||
if (system.getProvider() === 'ami') {
|
||||
if (typeof req.body.providerToken !== 'string' || !req.body.providerToken) return next(new HttpError(400, 'providerToken must be a non empty string'));
|
||||
|
||||
const [error, response] = await safe(superagent.get('http://169.254.169.254/latest/meta-data/instance-id').timeout(30 * 1000).ok(() => true));
|
||||
|
||||
// IMDSv2 https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-options.html
|
||||
// https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/
|
||||
const imdsIp = req.body.ipv4Config?.provider === 'noop' ? '[fd00:ec2::254]' : '169.254.169.254'; // use ipv4config carefully, it's not validated yet at this point
|
||||
const [tokenError, tokenResponse] = await safe(superagent.put(`http://${imdsIp}/latest/api/token`).set('x-aws-ec2-metadata-token-ttl-seconds', 600).timeout(30 * 1000).ok(() => true));
|
||||
if (tokenError) return next(new HttpError(422, `Network error getting EC2 metadata session token: ${tokenError.message}`));
|
||||
if (tokenResponse.status !== 200) return next(new HttpError(422, `Unable to get EC2 meta data session token. statusCode: ${tokenResponse.status}`));
|
||||
const imdsToken = tokenResponse.text;
|
||||
|
||||
const [error, response] = await safe(superagent.get(`http://${imdsIp}/latest/meta-data/instance-id`).set('x-aws-ec2-metadata-token', imdsToken).timeout(30 * 1000).ok(() => true));
|
||||
if (error) return next(new HttpError(422, `Network error getting EC2 metadata: ${error.message}`));
|
||||
if (response.status !== 200) return next(new HttpError(422, `Unable to get EC2 meta data. statusCode: ${response.status}`));
|
||||
if (response.text !== req.body.providerToken) return next(new HttpError(422, 'Instance ID does not match'));
|
||||
|
||||
Reference in New Issue
Block a user