Things of interest during development¶
Credential Provider responses¶
To determine what exceptions to raise, the following are the various scenarios and responses from the credential provider. All tests with invalid certificates don’t exercise all of these conditions, so the potentially known interactions with resources were exercised and documented. What was not tested was the use of an invalid certificate (e.g., one not registered with AWS IoT Core). In those cases, the underlying awscrt
raised errors were passed back to the calling function.
All tests assume a valid certificate and key registered with IoT Core. A ✅ indicates the proper association of the certificate with the other resources, while a ❌ means that is doesn’t. Further tests use the same ✅ / ❌ to delineate association of other resources.
For each test, the following were used:
IoT Policy -
test_iot_policy
(with and without credential allowed for permissions)IoT Role Alias -
test_role_alias
IAM Role -
test_iot_role_alias
(permissions are managed role for IoT Readonly)
The curl command used:
$ curl -v --cert thing1.pem --key thing1.key -H "x-amzn-iot-thingname: thing1" --cacert AmazonRootCA1.pem https://account_endpoint.credentials.iot.us-west-2.amazonaws.com/role-aliases/test_role_alias/credentials
* Trying 35.160.122.23:443...
* Connected to account_endpoint.credentials.iot.us-west-2.amazonaws.com (35.160.122.23) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
* CAfile: AmazonRootCA1.pem
* CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
...
< x-amzn-RequestId: 36ecd80d-bfc4-c9d0-0871-6bec7744a237
< x-amzn-ErrorType: AccessDeniedException
<
* Connection #0 to host account_endpoint.credentials.iot.us-west-2.amazonaws.com left intact
{"message":"Certificate is invalid on this endpoint"}%
The final line, which is the JSON payload of the body response was mapped with the status code.
Then for each combination of resources:
Thing |
IoT Policy |
IoT Policy Permissions |
IoT Role Alias |
IAM Role |
Role Alias Duration <= IAM Role |
Status Code |
Response Body |
---|---|---|---|---|---|---|---|
❌ |
❌ |
❌ |
❌ |
❌ |
❌ |
403 |
|
❌ |
✅ |
❌ |
❌ |
❌ |
❌ |
403 |
|
✅ |
✅ |
❌ |
❌ |
❌ |
❌ |
403 |
|
✅ |
✅ |
✅ |
❌ |
❌ |
❌ |
404 |
|
✅ |
✅ |
✅ |
✅ |
❌ |
❌ |
400 |
|
✅ |
✅ |
✅ |
✅ |
✅ |
❌ |
400 |
|
✅ |
✅ |
✅ |
✅ |
✅ |
✅ |
200 |
|
Local building and testing¶
The Hypermodern Python Cookiercutter documentation provides a good starting point. As this package supports various versions of Python to test and build against, the approach taken by the authors is to use asdf and direnv. The included .envrc
and .tool-versions
files contain the steps to locally create a virtualenv and reference locally installed Python versions.
The steps are (namely for me to remember!):
Fork and clone the repository
Enable GitHub actions prior to first commit and push
Ensure
asdf
anddirenv
are installedCreate a new local direnv via
direnv allow
, normally with the most recent version of PythonInstall build/text tools:
pip install poetry nox nox-poetry
poetry update && poetry install
Perform updates
nox
(will run all sessions)Create a pull request against the main repository
Once completed, commit the changes, verify the actions run in GitHub, then perform a pull request against the main repository. From the main repository, perform these steps:
Once all tests complete successfully, squash merge the pull request from the main repository
Locally, clone (or update) the main repository and follow the steps to install poetry and dependencies
git switch --create release main
poetry version <version>
(bump version based on semver)git commit --message="awsiot-credentialhelper <version>" pyproject.toml
git push origin release
Review results of Actions (they should still all pass), then create a pull request of this branch and merge-squash-delete.
Merging the pull requests triggers the Release workflow. Monitor that to ensure it has been published to PyPI.