diff --git a/.github/workflows/cdk.yml b/.github/workflows/cdk.yml new file mode 100644 index 0000000..a42e96e --- /dev/null +++ b/.github/workflows/cdk.yml @@ -0,0 +1,38 @@ +on: [push] + +jobs: + aws_cdk: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v2 + + - name: Set up Python 3.9 + uses: actions/setup-python@v2 + with: + python-version: '3.9' + + - name: Install AWS CDK + run: npm install -g aws-cdk + + - name: Install Pip dependencies + run: pip install -r requirements.txt + working-directory: 'api' + + - name: Bootstrap AWS CDK + run: cdk bootstrap + working-directory: 'api/infrastructure' + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: 'us-east-1' + + - name: CDK Deploy + run: cdk deploy --require-approval never + working-directory: 'api/infrastructure' + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: 'us-east-1' + STACK_NAME: 'sideload-reg-codes-github' + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4b49fd2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,136 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ +.vscode/ + +#MacOS File +.DS_Store + +# Infra +api/infrastructure/*.out diff --git a/README.md b/README.md index c2977b9..c8cd3b9 100644 --- a/README.md +++ b/README.md @@ -55,62 +55,66 @@ Below is a sequence diagram and overview diagram for this sample. This project has 2 parts: The IoT Client and the Registration API. -The registration API portion includes a CDK application and a Chalice application. These correspond to a +A. The registration API portion includes a CDK application and a Chalice application. These correspond to a ``infrastructure`` and ``runtime`` directory respectively. To run any CDK CLI commands, ensure you're in the ``infrastructure`` directory, and if you need to run any Chalice CLI commands, which you won't for this demo, ensure you're in the ``runtime`` directory. -The IoT client portion consists the client itself with the AWS IoT Python SDK, the aws_auth library for AWS SigV4 auth, +B. The IoT client portion consists the client itself with the AWS IoT Python SDK, the aws_auth library for AWS SigV4 auth, the requirements file with the required dependencies, and the Dockerfile. These are all stored under the `client` directory. ### Infrastructure and API deployment -First, you'll need to install the AWS CDK if you haven't already. The CDK requires Node.js and npm to run. +1. First, you'll need to install the AWS CDK if you haven't already. The CDK requires Node.js and npm to run. See the [Getting started with the AWS CDK](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html) for more details. ```bash npm install -g aws-cdk ``` - -Next you'll need to install the dependencies for the CDK deployment. - -There are two ways to do this. Either globally from the standard shell or using a virtual environment such as `pipenv` +2. Next you'll need to install the dependencies for the CDK deployment. There are two ways to do this. Either globally from the standard shell or using a virtual environment such as `pipenv` #### Installing dependencies with pipenv The recommended way to install Python dependencies is with a virtual environment such as Pipenv. There's an included Pipfile -with the repo that you can use to install all dependencies to run the client. First you'll need to make sure Pipenv is installed. -https://pipenv.pypa.io/en/latest/install/ +with the repo that you can use to install all dependencies to run the client. -Then you can use pipenv to install all the Python dependencies. -``` -pipenv install -``` +1. First you'll need to make sure Pipenv is installed using these instructions: https://pipenv.pypa.io/en/latest/install/ -Once all dependencies are installed, you'll need to activate the shell with `pipenv shell` +2. Then you can use pipenv to install all the Python dependencies. + ``` + pipenv install + ``` + +3. Once all dependencies are installed, you'll need to activate the shell with + ``` + pipenv shell + ``` #### Installing Dependencies Globally -From the root directory, switch to the `api` directory with `cd api` and then run -``` -pip install -r requirements.txt -``` +1. From the root directory, switch to the `api` directory with `cd api` and then run + ``` + pip install -r requirements.txt + ``` ### Deploying Code -Once the dependencies are installed, to work with the CDK and deploy your application, you'll need to change directories -to the ``infrastructure`` directory. +1. The CDK assets are stored in the infrastructure directory, so that's where you'll run all of your CDK commands out of. + ``` + cd infrastructure + ``` -1. If this is you're first time using the CDK you'll need to bootstrap your AWS account with the resouces the CDK needs. + +2. If this is you're first time using the CDK you'll need to bootstrap your AWS account with the resouces the CDK needs. ``` cdk bootstrap ``` -2. Now you're ready to deploy your application. +3. Now you're ready to deploy your application. ``` cdk deploy ``` @@ -118,7 +122,7 @@ to the ``infrastructure`` directory. Note: During deployment, the CDK will ask you to approve of the changes being created by CloudFormation, make sure to type `y` when prompted. -3. There will be two pieces of infrastructure left to manually provision that can not be deployed with CloudFormation, +4. There will be two pieces of infrastructure left to manually provision that can not be deployed with CloudFormation, and that's the AWS IoT Credential Provider role alias and the AWS IoT Thing Types. 1. The creation of the role alias can not be done via the console and must be done via a CLI command: @@ -241,4 +245,3 @@ See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more inform ## License This library is licensed under the MIT-0 License. See the LICENSE file. - diff --git a/api/buildspec.yaml b/api/buildspec.yaml index 3197492..b553bef 100644 --- a/api/buildspec.yaml +++ b/api/buildspec.yaml @@ -3,10 +3,10 @@ version: 0.2 phases: pre_build: commands: - - cd api/infrastructure - npm install -g cdk - - pip install -r requirements.txt + - pip install -r api/requirements.txt - echo Bootstrapping account for CDK + - cd api/infrastructure - cdk bootstrap build: commands: diff --git a/api/infrastructure/app.py b/api/infrastructure/app.py index bcfc337..66540ba 100644 --- a/api/infrastructure/app.py +++ b/api/infrastructure/app.py @@ -1,8 +1,10 @@ #!/usr/bin/env python3 +import os from aws_cdk import core as cdk from stacks.chaliceapp import ChaliceApp + app = cdk.App() -ChaliceApp(app, 'device-registration-api') +ChaliceApp(app, os.environ.get('STACK_NAME', 'device-registration-api')) app.synth() diff --git a/api/infrastructure/requirements.txt b/api/infrastructure/requirements.txt index 1a36c30..091f5b9 100644 --- a/api/infrastructure/requirements.txt +++ b/api/infrastructure/requirements.txt @@ -1,4 +1,4 @@ aws_cdk.core>=1.85.0,<2.0 aws_cdk.aws_dynamodb>=1.85.0,<2.0 aws_cdk.aws_iot>=1.85.0,<2.0 -chalice[cdk] \ No newline at end of file +chalice[cdk] diff --git a/api/infrastructure/stacks/__pycache__/__init__.cpython-39.pyc b/api/infrastructure/stacks/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..e6aa07f Binary files /dev/null and b/api/infrastructure/stacks/__pycache__/__init__.cpython-39.pyc differ diff --git a/api/infrastructure/stacks/__pycache__/chaliceapp.cpython-39.pyc b/api/infrastructure/stacks/__pycache__/chaliceapp.cpython-39.pyc new file mode 100644 index 0000000..aa0ba95 Binary files /dev/null and b/api/infrastructure/stacks/__pycache__/chaliceapp.cpython-39.pyc differ diff --git a/api/runtime/app.py b/api/runtime/app.py index fbb6974..9894f34 100644 --- a/api/runtime/app.py +++ b/api/runtime/app.py @@ -22,7 +22,7 @@ tenant_names = ['acme'] locations = ['bos', 'jfk', 'lax', 'sfo', 'atl', 'chi'] -device_type = ['deviceTypeA'] +device_types = ['deviceTypeA'] @app.route('/token', methods=['GET']) @@ -49,7 +49,7 @@ def create_token(): 'regToken': reg_token, 'location': random.choice(locations), 'tenant': random.choice(tenant_names), - 'deviceType': random.choice(device_type), + 'deviceType': random.choice(device_types), 'timestamp': int(time.time()), 'timesUsed': 0 }