diff --git a/changelogs/fragments/7.0.0-urls.yml b/changelogs/fragments/7.0.0-urls.yml new file mode 100644 index 00000000000..6181c64b35e --- /dev/null +++ b/changelogs/fragments/7.0.0-urls.yml @@ -0,0 +1,2 @@ +breaking_changes: +- module_utils - ``module_utils.urls`` was previously deprecated and has been removed (). diff --git a/galaxy.yml b/galaxy.yml index d11b71994a3..0199803c259 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,6 +1,6 @@ namespace: amazon name: aws -version: 6.0.0 +version: 7.0.0-dev0 readme: README.md authors: - Ansible (https://github.com/ansible) diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index 9bf2b477224..e7a1221ebf2 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -4,7 +4,7 @@ # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) AMAZON_AWS_COLLECTION_NAME = "amazon.aws" -AMAZON_AWS_COLLECTION_VERSION = "6.0.0" +AMAZON_AWS_COLLECTION_VERSION = "7.0.0-dev0" _collection_info_context = { diff --git a/plugins/module_utils/urls.py b/plugins/module_utils/urls.py deleted file mode 100644 index d723005a765..00000000000 --- a/plugins/module_utils/urls.py +++ /dev/null @@ -1,259 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Aaron Haaf -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -import datetime -import hashlib -import hmac -import operator - -try: - from boto3 import session -except ImportError: - pass - -from ansible.module_utils.six.moves.urllib.parse import urlencode -from ansible.module_utils.urls import open_url - -from .ec2 import HAS_BOTO3 -from .botocore import get_aws_connection_info - -import ansible.module_utils.common.warnings as ansible_warnings - - -def hexdigest(s): - """ - Returns the sha256 hexdigest of a string after encoding. - """ - - ansible_warnings.deprecate( - "amazon.aws.module_utils.urls.hexdigest is unused and has been deprecated.", - version="7.0.0", - collection_name="amazon.aws", - ) - - return hashlib.sha256(s.encode("utf-8")).hexdigest() - - -def format_querystring(params=None): - """ - Returns properly url-encoded query string from the provided params dict. - - It's specially sorted for cannonical requests - """ - - ansible_warnings.deprecate( - "amazon.aws.module_utils.urls.format_querystring is unused and has been deprecated.", - version="7.0.0", - collection_name="amazon.aws", - ) - - if not params: - return "" - - # Query string values must be URL-encoded (space=%20). The parameters must be sorted by name. - return urlencode(sorted(params.items(), operator.itemgetter(0))) - - -# Key derivation functions. See: -# http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-python -def sign(key, msg): - """ - Return digest for key applied to msg - """ - - ansible_warnings.deprecate( - "amazon.aws.module_utils.urls.sign is unused and has been deprecated.", - version="7.0.0", - collection_name="amazon.aws", - ) - - return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest() - - -def get_signature_key(key, dateStamp, regionName, serviceName): - """ - Returns signature key for AWS resource - """ - - ansible_warnings.deprecate( - "amazon.aws.module_utils.urls.get_signature_key is unused and has been deprecated.", - version="7.0.0", - collection_name="amazon.aws", - ) - - kDate = sign(("AWS4" + key).encode("utf-8"), dateStamp) - kRegion = sign(kDate, regionName) - kService = sign(kRegion, serviceName) - kSigning = sign(kService, "aws4_request") - return kSigning - - -def get_aws_credentials_object(module): - """ - Returns aws_access_key_id, aws_secret_access_key, session_token for a module. - """ - - ansible_warnings.deprecate( - "amazon.aws.module_utils.urls.get_aws_credentials_object is unused and has been deprecated.", - version="7.0.0", - collection_name="amazon.aws", - ) - - if not HAS_BOTO3: - module.fail_json("get_aws_credentials_object requires boto3") - - dummy, dummy, boto_params = get_aws_connection_info(module, boto3=True) - s = session.Session(**boto_params) - - return s.get_credentials() - - -# Reference: https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html -def signed_request( - module=None, - method="GET", - service=None, - host=None, - uri=None, - query=None, - body="", - headers=None, - session_in_header=True, - session_in_query=False, -): - """Generate a SigV4 request to an AWS resource for a module - - This is used if you wish to authenticate with AWS credentials to a secure endpoint like an elastisearch domain. - - Returns :class:`HTTPResponse` object. - - Example: - result = signed_request( - module=this, - service="es", - host="search-recipes1-xxxxxxxxx.us-west-2.es.amazonaws.com", - ) - - :kwarg host: endpoint to talk to - :kwarg service: AWS id of service (like `ec2` or `es`) - :kwarg module: An AnsibleAWSModule to gather connection info from - - :kwarg body: (optional) Payload to send - :kwarg method: (optional) HTTP verb to use - :kwarg query: (optional) dict of query params to handle - :kwarg uri: (optional) Resource path without query parameters - - :kwarg session_in_header: (optional) Add the session token to the headers - :kwarg session_in_query: (optional) Add the session token to the query parameters - - :returns: HTTPResponse - """ - - module.deprecate( - "amazon.aws.module_utils.urls.signed_request is unused and has been deprecated.", - version="7.0.0", - collection_name="amazon.aws", - ) - - if not HAS_BOTO3: - module.fail_json("A sigv4 signed_request requires boto3") - - # "Constants" - - t = datetime.datetime.utcnow() - amz_date = t.strftime("%Y%m%dT%H%M%SZ") - datestamp = t.strftime("%Y%m%d") # Date w/o time, used in credential scope - algorithm = "AWS4-HMAC-SHA256" - - # AWS stuff - - region, dummy, dummy = get_aws_connection_info(module, boto3=True) - credentials = get_aws_credentials_object(module) - access_key = credentials.access_key - secret_key = credentials.secret_key - session_token = credentials.token - - if not access_key: - module.fail_json(msg="aws_access_key_id is missing") - if not secret_key: - module.fail_json(msg="aws_secret_access_key is missing") - - credential_scope = "/".join([datestamp, region, service, "aws4_request"]) - - # Argument Defaults - - uri = uri or "/" - query_string = format_querystring(query) if query else "" - - headers = headers or dict() - query = query or dict() - - headers.update( - { - "host": host, - "x-amz-date": amz_date, - } - ) - - # Handle adding of session_token if present - if session_token: - if session_in_header: - headers["X-Amz-Security-Token"] = session_token - if session_in_query: - query["X-Amz-Security-Token"] = session_token - - if method == "GET": - body = "" - - # Derived data - - body_hash = hexdigest(body) - signed_headers = ";".join(sorted(headers.keys())) - - # Setup Cannonical request to generate auth token - - cannonical_headers = ( - "\n".join([key.lower().strip() + ":" + value for key, value in headers.items()]) + "\n" - ) # Note additional trailing newline - - cannonical_request = "\n".join( - [ - method, - uri, - query_string, - cannonical_headers, - signed_headers, - body_hash, - ] - ) - - string_to_sign = "\n".join([algorithm, amz_date, credential_scope, hexdigest(cannonical_request)]) - - # Sign the Cannonical request - - signing_key = get_signature_key(secret_key, datestamp, region, service) - signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest() - - # Make auth header with that info - - authorization_header = ( - f"{algorithm} Credential={access_key}/{credential_scope}, SignedHeaders={signed_headers}, Signature={signature}" - ) - - # PERFORM THE REQUEST! - - url = "https://" + host + uri - - if query_string != "": - url = url + "?" + query_string - - final_headers = { - "x-amz-date": amz_date, - "Authorization": authorization_header, - } - - final_headers.update(headers) - - return open_url(url, method=method, data=body, headers=final_headers)