|
| 1 | +# Example Signers for aws-sdk-signers |
| 2 | + |
| 3 | +## Requests |
| 4 | +We utilize the `AuthBase` construct provided by Requests to apply our signature |
| 5 | +to each request. Our `SigV4Auth` class takes two arguments |
| 6 | +[`SigV4SigningProperties`](https://github.com/smithy-lang/smithy-python/blob/9c0225b2810b3f68a84aa074e9b4e728a3043721/packages/aws-sdk-signers/src/aws_sdk_signers/signers.py#L44-L50) |
| 7 | +and an [`AWSCredentialIdentity`](https://github.com/smithy-lang/smithy-python/blob/9c0225b2810b3f68a84aa074e9b4e728a3043721/packages/aws-sdk-signers/src/aws_sdk_signers/_identity.py#L10-L15). |
| 8 | +These will be used across requests as "immutable" input. This is currently an |
| 9 | +intentional design decision to work with Requests auth design. We'd love to |
| 10 | +hear feedback on how you feel about the current approach, we recommend checking |
| 11 | +the AIOHTTP section below for an alternative design. |
| 12 | + |
| 13 | +### Requests Sample |
| 14 | +```python |
| 15 | +from os import environ |
| 16 | + |
| 17 | +import requests |
| 18 | + |
| 19 | +from examples import requests_signer |
| 20 | +from aws_sdk_signers import SigV4SigningProperties, AWSCredentialIdentity |
| 21 | + |
| 22 | +SERVICE="lambda" |
| 23 | +REGION="us-west-2" |
| 24 | + |
| 25 | +# A GET request to this URL performs a "ListFunctions" invocation. |
| 26 | +# Full API documentation can be found here: |
| 27 | +# https://docs.aws.amazon.com/lambda/latest/api/API_ListFunctions.html |
| 28 | +URL='https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/' |
| 29 | + |
| 30 | +def get_credentials_from_env(): |
| 31 | + """You will need to pull credentials from some source to use the signer. |
| 32 | + This will auto-populate an AWSCredentialIdentity when credentials are |
| 33 | + available through the env. |
| 34 | +
|
| 35 | + You may also consider using another SDK to assume a role or pull |
| 36 | + credentials from another source. |
| 37 | + """ |
| 38 | + return AWSCredentialIdentity( |
| 39 | + access_key_id=environ["AWS_ACCESS_KEY_ID"], |
| 40 | + secret_access_key=environ["AWS_SECRET_ACCESS_KEY"], |
| 41 | + session_token=environ.get("AWS_SESSION_TOKEN"), |
| 42 | + ) |
| 43 | + |
| 44 | +# Set up our properties and identity |
| 45 | +identity = get_credentials_from_env() |
| 46 | +properties = SigV4SigningProperties(region=REGION, service=SERVICE) |
| 47 | + |
| 48 | +# Configure the auth class for signing |
| 49 | +sigv4_auth = requests_signer.SigV4Auth(properties, identity) |
| 50 | + |
| 51 | +r = requests.get(URL, auth=sigv4_auth) |
| 52 | +``` |
| 53 | + |
| 54 | +## AIOHTTP |
| 55 | +For AIOHTTP, we don't have a concept of a Request object, or option to subclass an |
| 56 | +existing auth mechanism. Instead, we'll take parameters you normally pass to a Session |
| 57 | +method and use them to generate signing headers before passing them on to AIOHTTP. |
| 58 | + |
| 59 | +This signer will be configured the same way as Requests and provides an Async signing |
| 60 | +interface to be used alongside AIOHTTP. This is still a work in progress and will likely |
| 61 | +have some amount of iteration to improve performance and ergonomics as we collect feedback. |
| 62 | + |
| 63 | +### AIOHTTP Sample |
| 64 | +```python |
| 65 | +import asyncio |
| 66 | +from collections.abc import AsyncIterable, Mapping |
| 67 | +from os import environ |
| 68 | + |
| 69 | +import aiohttp |
| 70 | + |
| 71 | +from examples import aiohttp_signer |
| 72 | +from aws_sdk_signers import SigV4SigningProperties, AWSCredentialIdentity |
| 73 | + |
| 74 | + |
| 75 | +SERVICE="lambda" |
| 76 | +REGION="us-west-2" |
| 77 | + |
| 78 | +# A GET request to this URL performs a "ListFunctions" invocation. |
| 79 | +# Full API documentation can be found here: |
| 80 | +# https://docs.aws.amazon.com/lambda/latest/api/API_ListFunctions.html |
| 81 | +URL='https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/' |
| 82 | + |
| 83 | +def get_credentials_from_env(): |
| 84 | + """You will need to pull credentials from some source to use the signer. |
| 85 | + This will auto-populate an AWSCredentialIdentity when credentials are |
| 86 | + available through the env. |
| 87 | +
|
| 88 | + You may also consider using another SDK to assume a role or pull |
| 89 | + credentials from another source. |
| 90 | + """ |
| 91 | + return AWSCredentialIdentity( |
| 92 | + access_key_id=environ["AWS_ACCESS_KEY_ID"], |
| 93 | + secret_access_key=environ["AWS_SECRET_ACCESS_KEY"], |
| 94 | + session_token=environ.get("AWS_SESSION_TOKEN"), |
| 95 | + ) |
| 96 | + |
| 97 | +# Set up our signing_properties and identity |
| 98 | +identity = get_credentials_from_env() |
| 99 | +properties = SigV4SigningProperties(region=REGION, service=SERVICE) |
| 100 | + |
| 101 | +signer = aiohttp_signer.SigV4Signer(properties, identity) |
| 102 | + |
| 103 | +async def make_request( |
| 104 | + method: str, |
| 105 | + url: str, |
| 106 | + headers: Mapping[str, str], |
| 107 | + body: AsyncIterable[bytes] | None, |
| 108 | +) -> None: |
| 109 | + # For more robust applications, you'll likely want to reuse this session. |
| 110 | + async with aiohttp.ClientSession() as session: |
| 111 | + signing_headers = await signer.generate_signature(method, url, headers, body) |
| 112 | + headers.update(signing_headers) |
| 113 | + async with session.request(method, url, headers=headers, data=body) as response: |
| 114 | + print("Status:", response.status) |
| 115 | + print("Content-Type:", response.headers['content-type']) |
| 116 | + |
| 117 | + body_content = await response.text() |
| 118 | + print(body_content) |
| 119 | + |
| 120 | +asyncio.run(make_request("GET", URL, {}, None)) |
| 121 | +``` |
| 122 | + |
| 123 | +## Curl Signer |
| 124 | +For curl, we're generating a string to be used in a terminal or invoked subprocess. |
| 125 | +This currently only supports known arguments like defining the method, headers, |
| 126 | +and a request body. We can expand this to support arbitrary curl arguments in |
| 127 | +a future version if there's demand. |
| 128 | + |
| 129 | +### Curl Sample |
| 130 | +```python |
| 131 | +from examples import curl_signer |
| 132 | +from aws_sdk_signers import SigV4SigningProperties, AWSCredentialIdentity |
| 133 | + |
| 134 | +from os import environ |
| 135 | + |
| 136 | + |
| 137 | +SERVICE="lambda" |
| 138 | +REGION="us-west-2" |
| 139 | + |
| 140 | +# A GET request to this URL performs a "ListFunctions" invocation. |
| 141 | +# Full API documentation can be found here: |
| 142 | +# https://docs.aws.amazon.com/lambda/latest/api/API_ListFunctions.html |
| 143 | +URL='https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/' |
| 144 | + |
| 145 | + |
| 146 | +properties = SigV4SigningProperties(region=REGION, service=SERVICE) |
| 147 | +identity = AWSCredentialIdentity( |
| 148 | + access_key_id=environ["AWS_ACCESS_KEY_ID"], |
| 149 | + secret_access_key=environ["AWS_SECRET_ACCESS_KEY"], |
| 150 | + session_token=environ["AWS_SESSION_TOKEN"] |
| 151 | +) |
| 152 | + |
| 153 | +# Our curl signer doesn't need state so we |
| 154 | +# can call classmethods directly on the signer. |
| 155 | +signer = curl_signer.SigV4Curl |
| 156 | +curl_cmd = signer.generate_signed_curl_cmd( |
| 157 | + properties=properties, |
| 158 | + identity=identity, |
| 159 | + method="GET", |
| 160 | + url=URL, |
| 161 | + headers={}, |
| 162 | + body=None, |
| 163 | +) |
| 164 | +print(curl_cmd) |
| 165 | +``` |
0 commit comments