|
|
376cca |
From f6dc3cf39a4884657478a47894ce8a76ec9a72c5 Mon Sep 17 00:00:00 2001
|
|
|
9dab26 |
From: Eduardo Otubo <otubo@redhat.com>
|
|
|
376cca |
Date: Wed, 24 Jun 2020 07:34:29 +0200
|
|
|
376cca |
Subject: [PATCH 1/4] ec2: Do not log IMDSv2 token values, instead use REDACTED
|
|
|
9dab26 |
(#219)
|
|
|
9dab26 |
|
|
|
9dab26 |
RH-Author: Eduardo Otubo <otubo@redhat.com>
|
|
|
376cca |
Message-id: <20200505082940.18316-1-otubo@redhat.com>
|
|
|
376cca |
Patchwork-id: 96264
|
|
|
376cca |
O-Subject: [RHEL-7.9/RHEL-8.3 cloud-init PATCH] ec2: Do not log IMDSv2 token values, instead use REDACTED (#219)
|
|
|
376cca |
Bugzilla: 1822343
|
|
|
376cca |
RH-Acked-by: Cathy Avery <cavery@redhat.com>
|
|
|
9dab26 |
RH-Acked-by: Mohammed Gamal <mgamal@redhat.com>
|
|
|
376cca |
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
|
|
376cca |
|
|
|
376cca |
Note: There's no RHEL-8.3/cloud-init-19.4 branch yet, but it should be
|
|
|
376cca |
queued to be applied on top of it when it's created.
|
|
|
9dab26 |
|
|
|
9dab26 |
commit 87cd040ed8fe7195cbb357ed3bbf53cd2a81436c
|
|
|
9dab26 |
Author: Ryan Harper <ryan.harper@canonical.com>
|
|
|
9dab26 |
Date: Wed Feb 19 15:01:09 2020 -0600
|
|
|
9dab26 |
|
|
|
9dab26 |
ec2: Do not log IMDSv2 token values, instead use REDACTED (#219)
|
|
|
9dab26 |
|
|
|
9dab26 |
Instead of logging the token values used log the headers and replace the actual
|
|
|
9dab26 |
values with the string 'REDACTED'. This allows users to examine cloud-init.log
|
|
|
9dab26 |
and see that the IMDSv2 token header is being used but avoids leaving the value
|
|
|
9dab26 |
used in the log file itself.
|
|
|
9dab26 |
|
|
|
9dab26 |
LP: #1863943
|
|
|
9dab26 |
|
|
|
9dab26 |
Signed-off-by: Eduardo Otubo <otubo@redhat.com>
|
|
|
9dab26 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
9dab26 |
---
|
|
|
9dab26 |
cloudinit/ec2_utils.py | 12 ++++++++--
|
|
|
9dab26 |
cloudinit/sources/DataSourceEc2.py | 35 +++++++++++++++++++----------
|
|
|
9dab26 |
cloudinit/url_helper.py | 27 ++++++++++++++++------
|
|
|
9dab26 |
tests/unittests/test_datasource/test_ec2.py | 17 ++++++++++++++
|
|
|
9dab26 |
4 files changed, 70 insertions(+), 21 deletions(-)
|
|
|
9dab26 |
|
|
|
9dab26 |
diff --git a/cloudinit/ec2_utils.py b/cloudinit/ec2_utils.py
|
|
|
9dab26 |
index 57708c1..34acfe8 100644
|
|
|
9dab26 |
--- a/cloudinit/ec2_utils.py
|
|
|
9dab26 |
+++ b/cloudinit/ec2_utils.py
|
|
|
9dab26 |
@@ -142,7 +142,8 @@ def skip_retry_on_codes(status_codes, _request_args, cause):
|
|
|
9dab26 |
def get_instance_userdata(api_version='latest',
|
|
|
9dab26 |
metadata_address='http://169.254.169.254',
|
|
|
9dab26 |
ssl_details=None, timeout=5, retries=5,
|
|
|
9dab26 |
- headers_cb=None, exception_cb=None):
|
|
|
9dab26 |
+ headers_cb=None, headers_redact=None,
|
|
|
9dab26 |
+ exception_cb=None):
|
|
|
9dab26 |
ud_url = url_helper.combine_url(metadata_address, api_version)
|
|
|
9dab26 |
ud_url = url_helper.combine_url(ud_url, 'user-data')
|
|
|
9dab26 |
user_data = ''
|
|
|
9dab26 |
@@ -155,7 +156,8 @@ def get_instance_userdata(api_version='latest',
|
|
|
9dab26 |
SKIP_USERDATA_CODES)
|
|
|
9dab26 |
response = url_helper.read_file_or_url(
|
|
|
9dab26 |
ud_url, ssl_details=ssl_details, timeout=timeout,
|
|
|
9dab26 |
- retries=retries, exception_cb=exception_cb, headers_cb=headers_cb)
|
|
|
9dab26 |
+ retries=retries, exception_cb=exception_cb, headers_cb=headers_cb,
|
|
|
9dab26 |
+ headers_redact=headers_redact)
|
|
|
9dab26 |
user_data = response.contents
|
|
|
9dab26 |
except url_helper.UrlError as e:
|
|
|
9dab26 |
if e.code not in SKIP_USERDATA_CODES:
|
|
|
9dab26 |
@@ -169,11 +171,13 @@ def _get_instance_metadata(tree, api_version='latest',
|
|
|
9dab26 |
metadata_address='http://169.254.169.254',
|
|
|
9dab26 |
ssl_details=None, timeout=5, retries=5,
|
|
|
9dab26 |
leaf_decoder=None, headers_cb=None,
|
|
|
9dab26 |
+ headers_redact=None,
|
|
|
9dab26 |
exception_cb=None):
|
|
|
9dab26 |
md_url = url_helper.combine_url(metadata_address, api_version, tree)
|
|
|
9dab26 |
caller = functools.partial(
|
|
|
9dab26 |
url_helper.read_file_or_url, ssl_details=ssl_details,
|
|
|
9dab26 |
timeout=timeout, retries=retries, headers_cb=headers_cb,
|
|
|
9dab26 |
+ headers_redact=headers_redact,
|
|
|
9dab26 |
exception_cb=exception_cb)
|
|
|
9dab26 |
|
|
|
9dab26 |
def mcaller(url):
|
|
|
9dab26 |
@@ -197,6 +201,7 @@ def get_instance_metadata(api_version='latest',
|
|
|
9dab26 |
metadata_address='http://169.254.169.254',
|
|
|
9dab26 |
ssl_details=None, timeout=5, retries=5,
|
|
|
9dab26 |
leaf_decoder=None, headers_cb=None,
|
|
|
9dab26 |
+ headers_redact=None,
|
|
|
9dab26 |
exception_cb=None):
|
|
|
9dab26 |
# Note, 'meta-data' explicitly has trailing /.
|
|
|
9dab26 |
# this is required for CloudStack (LP: #1356855)
|
|
|
9dab26 |
@@ -204,6 +209,7 @@ def get_instance_metadata(api_version='latest',
|
|
|
9dab26 |
metadata_address=metadata_address,
|
|
|
9dab26 |
ssl_details=ssl_details, timeout=timeout,
|
|
|
9dab26 |
retries=retries, leaf_decoder=leaf_decoder,
|
|
|
9dab26 |
+ headers_redact=headers_redact,
|
|
|
9dab26 |
headers_cb=headers_cb,
|
|
|
9dab26 |
exception_cb=exception_cb)
|
|
|
9dab26 |
|
|
|
9dab26 |
@@ -212,12 +218,14 @@ def get_instance_identity(api_version='latest',
|
|
|
9dab26 |
metadata_address='http://169.254.169.254',
|
|
|
9dab26 |
ssl_details=None, timeout=5, retries=5,
|
|
|
9dab26 |
leaf_decoder=None, headers_cb=None,
|
|
|
9dab26 |
+ headers_redact=None,
|
|
|
9dab26 |
exception_cb=None):
|
|
|
9dab26 |
return _get_instance_metadata(tree='dynamic/instance-identity',
|
|
|
9dab26 |
api_version=api_version,
|
|
|
9dab26 |
metadata_address=metadata_address,
|
|
|
9dab26 |
ssl_details=ssl_details, timeout=timeout,
|
|
|
9dab26 |
retries=retries, leaf_decoder=leaf_decoder,
|
|
|
9dab26 |
+ headers_redact=headers_redact,
|
|
|
9dab26 |
headers_cb=headers_cb,
|
|
|
9dab26 |
exception_cb=exception_cb)
|
|
|
9dab26 |
# vi: ts=4 expandtab
|
|
|
9dab26 |
diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py
|
|
|
9dab26 |
index b9f346a..0f2bfef 100644
|
|
|
9dab26 |
--- a/cloudinit/sources/DataSourceEc2.py
|
|
|
9dab26 |
+++ b/cloudinit/sources/DataSourceEc2.py
|
|
|
9dab26 |
@@ -31,6 +31,9 @@ STRICT_ID_DEFAULT = "warn"
|
|
|
9dab26 |
API_TOKEN_ROUTE = 'latest/api/token'
|
|
|
9dab26 |
API_TOKEN_DISABLED = '_ec2_disable_api_token'
|
|
|
9dab26 |
AWS_TOKEN_TTL_SECONDS = '21600'
|
|
|
9dab26 |
+AWS_TOKEN_PUT_HEADER = 'X-aws-ec2-metadata-token'
|
|
|
9dab26 |
+AWS_TOKEN_REQ_HEADER = AWS_TOKEN_PUT_HEADER + '-ttl-seconds'
|
|
|
9dab26 |
+AWS_TOKEN_REDACT = [AWS_TOKEN_PUT_HEADER, AWS_TOKEN_REQ_HEADER]
|
|
|
9dab26 |
|
|
|
9dab26 |
|
|
|
9dab26 |
class CloudNames(object):
|
|
|
9dab26 |
@@ -158,7 +161,8 @@ class DataSourceEc2(sources.DataSource):
|
|
|
9dab26 |
for api_ver in self.extended_metadata_versions:
|
|
|
9dab26 |
url = url_tmpl.format(self.metadata_address, api_ver)
|
|
|
9dab26 |
try:
|
|
|
9dab26 |
- resp = uhelp.readurl(url=url, headers=headers)
|
|
|
9dab26 |
+ resp = uhelp.readurl(url=url, headers=headers,
|
|
|
9dab26 |
+ headers_redact=AWS_TOKEN_REDACT)
|
|
|
9dab26 |
except uhelp.UrlError as e:
|
|
|
9dab26 |
LOG.debug('url %s raised exception %s', url, e)
|
|
|
9dab26 |
else:
|
|
|
9dab26 |
@@ -180,6 +184,7 @@ class DataSourceEc2(sources.DataSource):
|
|
|
9dab26 |
self.identity = ec2.get_instance_identity(
|
|
|
9dab26 |
api_version, self.metadata_address,
|
|
|
9dab26 |
headers_cb=self._get_headers,
|
|
|
9dab26 |
+ headers_redact=AWS_TOKEN_REDACT,
|
|
|
9dab26 |
exception_cb=self._refresh_stale_aws_token_cb).get(
|
|
|
9dab26 |
'document', {})
|
|
|
9dab26 |
return self.identity.get(
|
|
|
9dab26 |
@@ -205,7 +210,8 @@ class DataSourceEc2(sources.DataSource):
|
|
|
9dab26 |
LOG.debug('Fetching Ec2 IMDSv2 API Token')
|
|
|
9dab26 |
url, response = uhelp.wait_for_url(
|
|
|
9dab26 |
urls=urls, max_wait=1, timeout=1, status_cb=self._status_cb,
|
|
|
9dab26 |
- headers_cb=self._get_headers, request_method=request_method)
|
|
|
9dab26 |
+ headers_cb=self._get_headers, request_method=request_method,
|
|
|
9dab26 |
+ headers_redact=AWS_TOKEN_REDACT)
|
|
|
9dab26 |
|
|
|
9dab26 |
if url and response:
|
|
|
9dab26 |
self._api_token = response
|
|
|
9dab26 |
@@ -252,7 +258,8 @@ class DataSourceEc2(sources.DataSource):
|
|
|
9dab26 |
url, _ = uhelp.wait_for_url(
|
|
|
9dab26 |
urls=urls, max_wait=url_params.max_wait_seconds,
|
|
|
9dab26 |
timeout=url_params.timeout_seconds, status_cb=LOG.warning,
|
|
|
9dab26 |
- headers_cb=self._get_headers, request_method=request_method)
|
|
|
9dab26 |
+ headers_redact=AWS_TOKEN_REDACT, headers_cb=self._get_headers,
|
|
|
9dab26 |
+ request_method=request_method)
|
|
|
9dab26 |
|
|
|
9dab26 |
if url:
|
|
|
9dab26 |
metadata_address = url2base[url]
|
|
|
9dab26 |
@@ -420,6 +427,7 @@ class DataSourceEc2(sources.DataSource):
|
|
|
9dab26 |
if not self.wait_for_metadata_service():
|
|
|
9dab26 |
return {}
|
|
|
9dab26 |
api_version = self.get_metadata_api_version()
|
|
|
9dab26 |
+ redact = AWS_TOKEN_REDACT
|
|
|
9dab26 |
crawled_metadata = {}
|
|
|
9dab26 |
if self.cloud_name == CloudNames.AWS:
|
|
|
9dab26 |
exc_cb = self._refresh_stale_aws_token_cb
|
|
|
9dab26 |
@@ -429,14 +437,17 @@ class DataSourceEc2(sources.DataSource):
|
|
|
9dab26 |
try:
|
|
|
9dab26 |
crawled_metadata['user-data'] = ec2.get_instance_userdata(
|
|
|
9dab26 |
api_version, self.metadata_address,
|
|
|
9dab26 |
- headers_cb=self._get_headers, exception_cb=exc_cb_ud)
|
|
|
9dab26 |
+ headers_cb=self._get_headers, headers_redact=redact,
|
|
|
9dab26 |
+ exception_cb=exc_cb_ud)
|
|
|
9dab26 |
crawled_metadata['meta-data'] = ec2.get_instance_metadata(
|
|
|
9dab26 |
api_version, self.metadata_address,
|
|
|
9dab26 |
- headers_cb=self._get_headers, exception_cb=exc_cb)
|
|
|
9dab26 |
+ headers_cb=self._get_headers, headers_redact=redact,
|
|
|
9dab26 |
+ exception_cb=exc_cb)
|
|
|
9dab26 |
if self.cloud_name == CloudNames.AWS:
|
|
|
9dab26 |
identity = ec2.get_instance_identity(
|
|
|
9dab26 |
api_version, self.metadata_address,
|
|
|
9dab26 |
- headers_cb=self._get_headers, exception_cb=exc_cb)
|
|
|
9dab26 |
+ headers_cb=self._get_headers, headers_redact=redact,
|
|
|
9dab26 |
+ exception_cb=exc_cb)
|
|
|
9dab26 |
crawled_metadata['dynamic'] = {'instance-identity': identity}
|
|
|
9dab26 |
except Exception:
|
|
|
9dab26 |
util.logexc(
|
|
|
9dab26 |
@@ -455,11 +466,12 @@ class DataSourceEc2(sources.DataSource):
|
|
|
9dab26 |
if self.cloud_name != CloudNames.AWS:
|
|
|
9dab26 |
return None
|
|
|
9dab26 |
LOG.debug("Refreshing Ec2 metadata API token")
|
|
|
9dab26 |
- request_header = {'X-aws-ec2-metadata-token-ttl-seconds': seconds}
|
|
|
9dab26 |
+ request_header = {AWS_TOKEN_REQ_HEADER: seconds}
|
|
|
9dab26 |
token_url = '{}/{}'.format(self.metadata_address, API_TOKEN_ROUTE)
|
|
|
9dab26 |
try:
|
|
|
9dab26 |
- response = uhelp.readurl(
|
|
|
9dab26 |
- token_url, headers=request_header, request_method="PUT")
|
|
|
9dab26 |
+ response = uhelp.readurl(token_url, headers=request_header,
|
|
|
9dab26 |
+ headers_redact=AWS_TOKEN_REDACT,
|
|
|
9dab26 |
+ request_method="PUT")
|
|
|
9dab26 |
except uhelp.UrlError as e:
|
|
|
9dab26 |
LOG.warning(
|
|
|
9dab26 |
'Unable to get API token: %s raised exception %s',
|
|
|
9dab26 |
@@ -500,8 +512,7 @@ class DataSourceEc2(sources.DataSource):
|
|
|
9dab26 |
API_TOKEN_DISABLED):
|
|
|
9dab26 |
return {}
|
|
|
9dab26 |
# Request a 6 hour token if URL is API_TOKEN_ROUTE
|
|
|
9dab26 |
- request_token_header = {
|
|
|
9dab26 |
- 'X-aws-ec2-metadata-token-ttl-seconds': AWS_TOKEN_TTL_SECONDS}
|
|
|
9dab26 |
+ request_token_header = {AWS_TOKEN_REQ_HEADER: AWS_TOKEN_TTL_SECONDS}
|
|
|
9dab26 |
if API_TOKEN_ROUTE in url:
|
|
|
9dab26 |
return request_token_header
|
|
|
9dab26 |
if not self._api_token:
|
|
|
9dab26 |
@@ -511,7 +522,7 @@ class DataSourceEc2(sources.DataSource):
|
|
|
9dab26 |
self._api_token = self._refresh_api_token()
|
|
|
9dab26 |
if not self._api_token:
|
|
|
9dab26 |
return {}
|
|
|
9dab26 |
- return {'X-aws-ec2-metadata-token': self._api_token}
|
|
|
9dab26 |
+ return {AWS_TOKEN_PUT_HEADER: self._api_token}
|
|
|
9dab26 |
|
|
|
9dab26 |
|
|
|
9dab26 |
class DataSourceEc2Local(DataSourceEc2):
|
|
|
9dab26 |
diff --git a/cloudinit/url_helper.py b/cloudinit/url_helper.py
|
|
|
9dab26 |
index 1496a47..3e7de9f 100644
|
|
|
9dab26 |
--- a/cloudinit/url_helper.py
|
|
|
9dab26 |
+++ b/cloudinit/url_helper.py
|
|
|
9dab26 |
@@ -8,6 +8,7 @@
|
|
|
9dab26 |
#
|
|
|
9dab26 |
# This file is part of cloud-init. See LICENSE file for license information.
|
|
|
9dab26 |
|
|
|
9dab26 |
+import copy
|
|
|
9dab26 |
import json
|
|
|
9dab26 |
import os
|
|
|
9dab26 |
import requests
|
|
|
9dab26 |
@@ -41,6 +42,7 @@ else:
|
|
|
9dab26 |
SSL_ENABLED = False
|
|
|
9dab26 |
CONFIG_ENABLED = False # This was added in 0.7 (but taken out in >=1.0)
|
|
|
9dab26 |
_REQ_VER = None
|
|
|
9dab26 |
+REDACTED = 'REDACTED'
|
|
|
9dab26 |
try:
|
|
|
9dab26 |
from distutils.version import LooseVersion
|
|
|
9dab26 |
import pkg_resources
|
|
|
9dab26 |
@@ -199,9 +201,9 @@ def _get_ssl_args(url, ssl_details):
|
|
|
9dab26 |
|
|
|
9dab26 |
|
|
|
9dab26 |
def readurl(url, data=None, timeout=None, retries=0, sec_between=1,
|
|
|
9dab26 |
- headers=None, headers_cb=None, ssl_details=None,
|
|
|
9dab26 |
- check_status=True, allow_redirects=True, exception_cb=None,
|
|
|
9dab26 |
- session=None, infinite=False, log_req_resp=True,
|
|
|
9dab26 |
+ headers=None, headers_cb=None, headers_redact=None,
|
|
|
9dab26 |
+ ssl_details=None, check_status=True, allow_redirects=True,
|
|
|
9dab26 |
+ exception_cb=None, session=None, infinite=False, log_req_resp=True,
|
|
|
9dab26 |
request_method=None):
|
|
|
9dab26 |
"""Wrapper around requests.Session to read the url and retry if necessary
|
|
|
9dab26 |
|
|
|
9dab26 |
@@ -217,6 +219,7 @@ def readurl(url, data=None, timeout=None, retries=0, sec_between=1,
|
|
|
9dab26 |
:param headers: Optional dict of headers to send during request
|
|
|
9dab26 |
:param headers_cb: Optional callable returning a dict of values to send as
|
|
|
9dab26 |
headers during request
|
|
|
9dab26 |
+ :param headers_redact: Optional list of header names to redact from the log
|
|
|
9dab26 |
:param ssl_details: Optional dict providing key_file, ca_certs, and
|
|
|
9dab26 |
cert_file keys for use on in ssl connections.
|
|
|
9dab26 |
:param check_status: Optional boolean set True to raise when HTTPError
|
|
|
9dab26 |
@@ -243,6 +246,8 @@ def readurl(url, data=None, timeout=None, retries=0, sec_between=1,
|
|
|
9dab26 |
req_args['method'] = request_method
|
|
|
9dab26 |
if timeout is not None:
|
|
|
9dab26 |
req_args['timeout'] = max(float(timeout), 0)
|
|
|
9dab26 |
+ if headers_redact is None:
|
|
|
9dab26 |
+ headers_redact = []
|
|
|
9dab26 |
# It doesn't seem like config
|
|
|
9dab26 |
# was added in older library versions (or newer ones either), thus we
|
|
|
9dab26 |
# need to manually do the retries if it wasn't...
|
|
|
9dab26 |
@@ -287,6 +292,12 @@ def readurl(url, data=None, timeout=None, retries=0, sec_between=1,
|
|
|
9dab26 |
if k == 'data':
|
|
|
9dab26 |
continue
|
|
|
9dab26 |
filtered_req_args[k] = v
|
|
|
9dab26 |
+ if k == 'headers':
|
|
|
9dab26 |
+ for hkey, _hval in v.items():
|
|
|
9dab26 |
+ if hkey in headers_redact:
|
|
|
9dab26 |
+ filtered_req_args[k][hkey] = (
|
|
|
9dab26 |
+ copy.deepcopy(req_args[k][hkey]))
|
|
|
9dab26 |
+ filtered_req_args[k][hkey] = REDACTED
|
|
|
9dab26 |
try:
|
|
|
9dab26 |
|
|
|
9dab26 |
if log_req_resp:
|
|
|
9dab26 |
@@ -339,8 +350,8 @@ def readurl(url, data=None, timeout=None, retries=0, sec_between=1,
|
|
|
9dab26 |
return None # Should throw before this...
|
|
|
9dab26 |
|
|
|
9dab26 |
|
|
|
9dab26 |
-def wait_for_url(urls, max_wait=None, timeout=None,
|
|
|
9dab26 |
- status_cb=None, headers_cb=None, sleep_time=1,
|
|
|
9dab26 |
+def wait_for_url(urls, max_wait=None, timeout=None, status_cb=None,
|
|
|
9dab26 |
+ headers_cb=None, headers_redact=None, sleep_time=1,
|
|
|
9dab26 |
exception_cb=None, sleep_time_cb=None, request_method=None):
|
|
|
9dab26 |
"""
|
|
|
9dab26 |
urls: a list of urls to try
|
|
|
9dab26 |
@@ -352,6 +363,7 @@ def wait_for_url(urls, max_wait=None, timeout=None,
|
|
|
9dab26 |
status_cb: call method with string message when a url is not available
|
|
|
9dab26 |
headers_cb: call method with single argument of url to get headers
|
|
|
9dab26 |
for request.
|
|
|
9dab26 |
+ headers_redact: a list of header names to redact from the log
|
|
|
9dab26 |
exception_cb: call method with 2 arguments 'msg' (per status_cb) and
|
|
|
9dab26 |
'exception', the exception that occurred.
|
|
|
9dab26 |
sleep_time_cb: call method with 2 arguments (response, loop_n) that
|
|
|
9dab26 |
@@ -415,8 +427,9 @@ def wait_for_url(urls, max_wait=None, timeout=None,
|
|
|
9dab26 |
headers = {}
|
|
|
9dab26 |
|
|
|
9dab26 |
response = readurl(
|
|
|
9dab26 |
- url, headers=headers, timeout=timeout,
|
|
|
9dab26 |
- check_status=False, request_method=request_method)
|
|
|
9dab26 |
+ url, headers=headers, headers_redact=headers_redact,
|
|
|
9dab26 |
+ timeout=timeout, check_status=False,
|
|
|
9dab26 |
+ request_method=request_method)
|
|
|
9dab26 |
if not response.contents:
|
|
|
9dab26 |
reason = "empty response [%s]" % (response.code)
|
|
|
9dab26 |
url_exc = UrlError(ValueError(reason), code=response.code,
|
|
|
9dab26 |
diff --git a/tests/unittests/test_datasource/test_ec2.py b/tests/unittests/test_datasource/test_ec2.py
|
|
|
9dab26 |
index 34a089f..bd5bd4c 100644
|
|
|
9dab26 |
--- a/tests/unittests/test_datasource/test_ec2.py
|
|
|
9dab26 |
+++ b/tests/unittests/test_datasource/test_ec2.py
|
|
|
9dab26 |
@@ -429,6 +429,23 @@ class TestEc2(test_helpers.HttprettyTestCase):
|
|
|
9dab26 |
self.assertTrue(ds.get_data())
|
|
|
9dab26 |
self.assertFalse(ds.is_classic_instance())
|
|
|
9dab26 |
|
|
|
9dab26 |
+ def test_aws_token_redacted(self):
|
|
|
9dab26 |
+ """Verify that aws tokens are redacted when logged."""
|
|
|
9dab26 |
+ ds = self._setup_ds(
|
|
|
9dab26 |
+ platform_data=self.valid_platform_data,
|
|
|
9dab26 |
+ sys_cfg={'datasource': {'Ec2': {'strict_id': False}}},
|
|
|
9dab26 |
+ md={'md': DEFAULT_METADATA})
|
|
|
9dab26 |
+ self.assertTrue(ds.get_data())
|
|
|
9dab26 |
+ all_logs = self.logs.getvalue().splitlines()
|
|
|
9dab26 |
+ REDACT_TTL = "'X-aws-ec2-metadata-token-ttl-seconds': 'REDACTED'"
|
|
|
9dab26 |
+ REDACT_TOK = "'X-aws-ec2-metadata-token': 'REDACTED'"
|
|
|
9dab26 |
+ logs_with_redacted_ttl = [log for log in all_logs if REDACT_TTL in log]
|
|
|
9dab26 |
+ logs_with_redacted = [log for log in all_logs if REDACT_TOK in log]
|
|
|
9dab26 |
+ logs_with_token = [log for log in all_logs if 'API-TOKEN' in log]
|
|
|
9dab26 |
+ self.assertEqual(1, len(logs_with_redacted_ttl))
|
|
|
9dab26 |
+ self.assertEqual(79, len(logs_with_redacted))
|
|
|
9dab26 |
+ self.assertEqual(0, len(logs_with_token))
|
|
|
9dab26 |
+
|
|
|
9dab26 |
@mock.patch('cloudinit.net.dhcp.maybe_perform_dhcp_discovery')
|
|
|
9dab26 |
def test_valid_platform_with_strict_true(self, m_dhcp):
|
|
|
9dab26 |
"""Valid platform data should return true with strict_id true."""
|
|
|
9dab26 |
--
|
|
|
9dab26 |
1.8.3.1
|
|
|
9dab26 |
|