From 6a9de07a4ced34845edf5dfce0f22d2399bf78d9 Mon Sep 17 00:00:00 2001 From: Matthew Pugh Date: Sat, 23 Nov 2024 00:33:30 +0000 Subject: [PATCH 1/3] Initial setup to modify user groups and connect to the cognito trigger --- .../full/common/cognito_pool_triggers.yaml | 65 ++++ .../full/common/lambda/assign_group/README.md | 28 ++ .../assign_group/assign_group/__init__.py | 0 .../assign_group/assign_group/handler.py | 41 ++ .../common/lambda/assign_group/poetry.lock | 367 ++++++++++++++++++ .../common/lambda/assign_group/pyproject.toml | 19 + .../lambda/assign_group/tests/__init__.py | 0 .../lambda/assign_group/tests/test_handler.py | 39 ++ .../cloudformation/full/la/sso1.yaml | 20 +- .../full/organisation/sso1.yaml | 18 - 10 files changed, 561 insertions(+), 36 deletions(-) create mode 100644 infrastructure/environments/cloudformation/full/common/cognito_pool_triggers.yaml create mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/README.md create mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/__init__.py create mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/handler.py create mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/poetry.lock create mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/pyproject.toml create mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/__init__.py create mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/test_handler.py diff --git a/infrastructure/environments/cloudformation/full/common/cognito_pool_triggers.yaml b/infrastructure/environments/cloudformation/full/common/cognito_pool_triggers.yaml new file mode 100644 index 0000000..4d34d4e --- /dev/null +++ b/infrastructure/environments/cloudformation/full/common/cognito_pool_triggers.yaml @@ -0,0 +1,65 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: | + This template adds cognito triggers to handle post-authentication tasks + + +Parameters: + DataStoreLocationArn: + Description: The S3 Bucket users will have access to for uploading files + Type: String + LambdaCodeBucket: + Description: Bucket where code is located for Lambda functions + Type: String + +Resources: + GroupAssignLambda: + Type: AWS::Lambda::Function + Properties: + Code: + S3Bucket: !Ref LambdaCodeBucket + S3Key: group-assign-lambda.zip + Role: !GetAtt GroupAssignLambdaRole.Arn + Handler: handler.lambda_handler + Runtime: python3.11 + Timeout: 60 + Environment: + Variables: + USER_POOL_ID: !Ref CognitoUserPool + GROUP_NAME: !Ref GeneralAccessGroup + ENVIRONMENT: !Ref Environment + + GeneralUserRole: + Type: AWS::IAM::Role + Properties: + RoleName: GeneralUserRole + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: ec2.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: GeneralUserPolicy + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: AllowFrontendDataStoreBucketAccess + Effect: Allow + Action: + - "s3:DeleteObject" + - "s3:GetObject" + - "s3:ListBucket" + - "s3:PutObject" + - "s3:PutObjectAcl" + Resource: + - !Sub "${DataStoreLocationArn}" + - !Sub "${DataStoreLocationArn}/*" + + GeneralAccessGroup: + Type: AWS::Cognito::UserPoolGroup + Properties: + GroupName: "GeneralUserAccess" + Precedence: 0 + RoleArn: !Ref FrontendPermissionRoleARN + UserPoolId: !Ref CognitoUserPool diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/README.md b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/README.md new file mode 100644 index 0000000..7a7b0a7 --- /dev/null +++ b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/README.md @@ -0,0 +1,28 @@ +# Scaling Lambda + +## Manual Process +To package this, do the following: + +1. If it doesn't exist, make the package directory +```commandline +mkdir package +``` +2. Next, we want to ensure all the libraries are present in the package: +```commandline +poetry run pip install --target ./package boto3 +``` +3. Zip Everything Up +```commandline +cd package +zip -r ../assign-group-lambda.zip +``` +4. Add the lambda function handler to the zip +```commandline +cd ../assign_group +zip ../assign-group-lambda.zip ./handler.py +``` +5. The zip should have a flat directory structure, ready to be uploaded to s3 + +## Automated Process +To do. The above process could be done via a github actions and then an upload step could push this to s3, +and redeployed to the lambda. \ No newline at end of file diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/__init__.py b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/handler.py b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/handler.py new file mode 100644 index 0000000..e81d1c7 --- /dev/null +++ b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/handler.py @@ -0,0 +1,41 @@ +""" +This module assigns a user to a standard user group after they login. +""" +import logging +import boto3 + +def lambda_handler(event, context): + """ + :param event: AWS Lambda event object containing Cognito sign-in information + :param context: AWS Lambda context object + :return: Modified event with successful processing + """ + cognito_idp = boto3.client("cognito-idp") + + try: + user_pool_id = event["userPoolId"] + username = event["userName"] + except KeyError as err: + logging.error("Could not get required information from event: %s", err) + raise + + try: + cognito_idp.admin_add_user_to_group( + UserPoolId=user_pool_id, Username=username, GroupName="GeneralUserAccess" + ) + except cognito_idp.Client.exceptions.InvalidParameterException as err: + logging.error("Invalid parameter specified when assigning to group: %s", err) + except cognito_idp.Client.exceptions.ResourceNotFoundException as err: + logging.error("Can't find user pool") + except cognito_idp.Client.exceptions.TooManyRequestsException: + logging.error( + "User group assignment failed due to too many requests on the service" + ) + except cognito_idp.Client.exceptions.NotAuthorizedException: + logging.error("Don't have permission to add user to group") + except cognito_idp.Client.exceptions.UserNotFoundException: + logging.error("User not found in pool") + except Exception as err: + logging.error("An unexpected error has occurred: %s", err) + + return event diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/poetry.lock b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/poetry.lock new file mode 100644 index 0000000..af2522f --- /dev/null +++ b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/poetry.lock @@ -0,0 +1,367 @@ +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. + +[[package]] +name = "astroid" +version = "3.3.5" +description = "An abstract syntax tree for Python with inference support." +optional = false +python-versions = ">=3.9.0" +files = [ + {file = "astroid-3.3.5-py3-none-any.whl", hash = "sha256:a9d1c946ada25098d790e079ba2a1b112157278f3fb7e718ae6a9252f5835dc8"}, + {file = "astroid-3.3.5.tar.gz", hash = "sha256:5cfc40ae9f68311075d27ef68a4841bdc5cc7f6cf86671b49f00607d30188e2d"}, +] + +[[package]] +name = "black" +version = "24.10.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.9" +files = [ + {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, + {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, + {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, + {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, + {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, + {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, + {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, + {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, + {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, + {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, + {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.10)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "boto3" +version = "1.35.68" +description = "The AWS SDK for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "boto3-1.35.68-py3-none-any.whl", hash = "sha256:9b26fa31901da7793c1dcd65eee9bab7e897d8aa1ffed0b5e1c3bce93d2aefe4"}, + {file = "boto3-1.35.68.tar.gz", hash = "sha256:091d6bed1422370987a839bff3f8755df7404fc15e9fac2a48e8505356f07433"}, +] + +[package.dependencies] +botocore = ">=1.35.68,<1.36.0" +jmespath = ">=0.7.1,<2.0.0" +s3transfer = ">=0.10.0,<0.11.0" + +[package.extras] +crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] + +[[package]] +name = "botocore" +version = "1.35.68" +description = "Low-level, data-driven core of boto 3." +optional = false +python-versions = ">=3.8" +files = [ + {file = "botocore-1.35.68-py3-none-any.whl", hash = "sha256:599139d5564291f5be873800711f9e4e14a823395ae9ce7b142be775e9849b94"}, + {file = "botocore-1.35.68.tar.gz", hash = "sha256:42c3700583a82f2b5316281a073d644a521d6358837e2b446dc458ba5d990fb4"}, +] + +[package.dependencies] +jmespath = ">=0.7.1,<2.0.0" +python-dateutil = ">=2.1,<3.0.0" +urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} + +[package.extras] +crt = ["awscrt (==0.22.0)"] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "dill" +version = "0.3.9" +description = "serialize all of Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, + {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "isort" +version = "5.13.2" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] + +[package.extras] +colors = ["colorama (>=0.4.6)"] + +[[package]] +name = "jmespath" +version = "1.0.1" +description = "JSON Matching Expressions" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, + {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "packaging" +version = "24.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pylint" +version = "3.3.1" +description = "python code static checker" +optional = false +python-versions = ">=3.9.0" +files = [ + {file = "pylint-3.3.1-py3-none-any.whl", hash = "sha256:2f846a466dd023513240bc140ad2dd73bfc080a5d85a710afdb728c420a5a2b9"}, + {file = "pylint-3.3.1.tar.gz", hash = "sha256:9f3dcc87b1203e612b78d91a896407787e708b3f189b5fa0b307712d49ff0c6e"}, +] + +[package.dependencies] +astroid = ">=3.3.4,<=3.4.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = [ + {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, +] +isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomlkit = ">=0.10.1" + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pytest" +version = "8.3.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2" + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "s3transfer" +version = "0.10.4" +description = "An Amazon S3 Transfer Manager" +optional = false +python-versions = ">=3.8" +files = [ + {file = "s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e"}, + {file = "s3transfer-0.10.4.tar.gz", hash = "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7"}, +] + +[package.dependencies] +botocore = ">=1.33.2,<2.0a.0" + +[package.extras] +crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "tomlkit" +version = "0.13.2" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, + {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, +] + +[[package]] +name = "urllib3" +version = "2.2.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.11" +content-hash = "48844298edfae164532bbd8e5b417a2c075bc5bf47e30646022a37be1376ec77" diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/pyproject.toml b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/pyproject.toml new file mode 100644 index 0000000..3c30a0b --- /dev/null +++ b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/pyproject.toml @@ -0,0 +1,19 @@ +[tool.poetry] +name = "assign group lambda" +version = "0.1.0" +description = "Assigns user groups to users who log into the system" +authors = ["Matthew Pugh "] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.11" +boto3 = "^1.35.67" + +[tool.poetry.group.dev.dependencies] +pytest = "^8.3.3" +black = "^24.10.0" +pylint = "^3.3.1" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/__init__.py b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/test_handler.py b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/test_handler.py new file mode 100644 index 0000000..17365da --- /dev/null +++ b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/test_handler.py @@ -0,0 +1,39 @@ +import unittest +from unittest.mock import patch, Mock, call, MagicMock +from assign_group.handler import lambda_handler + + +class TestLambdaHandler(unittest.TestCase): + @patch("os.environ.get") + @patch("boto3.client") + def test_lambda_handler(self, mock_boto_client, mock_get_env): + mock_idp_client = Mock() + mock_boto_client.return_value = mock_idp_client + + event = {"userPoolId": "test_pool_a890", "userName": "test.user"} + + res = lambda_handler(event, None) + + assert res == event + + mock_idp_client.admin_add_user_to_group.assert_has_calls( + [ + call( + UserPoolId=event["userPoolId"], + Username=event["userName"], + GroupName="GeneralUserAccess", + ) + ] + ) + + @patch("os.environ.get") + @patch("boto3.client") + def test_lambda_handler_missing_keys(self, mock_boto_client, mock_get_env): + mock_idp_client = Mock() + mock_boto_client.return_value = mock_idp_client + + event = {} + with self.assertRaises(KeyError) as context: + res = lambda_handler(event, None) + + mock_idp_client.admin_add_user_to_group.assert_not_called() diff --git a/infrastructure/environments/cloudformation/full/la/sso1.yaml b/infrastructure/environments/cloudformation/full/la/sso1.yaml index 765c17e..fa055b7 100644 --- a/infrastructure/environments/cloudformation/full/la/sso1.yaml +++ b/infrastructure/environments/cloudformation/full/la/sso1.yaml @@ -37,24 +37,8 @@ Resources: RequireSymbols: true VerificationMessageTemplate: DefaultEmailOption: CONFIRM_WITH_LINK - - #CognitoUserPoolClient: - # Type: AWS::Cognito::UserPoolClient - # Properties: - # ClientName: !Sub "${ApplicationName}-${OrganisationName}-cognito-client-${EnvironmentName}" - # UserPoolId: !Ref CognitoUserPool - # GenerateSecret: true - # AllowedOAuthFlows: - # - code - # - implicit - # AllowedOAuthScopes: - # - email - # - aws.cognito.signin.user.admin - # - openid - # LogoutURLs: - # - !Ref LogoutURL - # CallbackURLs: - # - !Ref CallbackURL + LambdaConfig: + PostConfirmation: !Ref GroupAssignLambda UserPoolDomain: Type: AWS::Cognito::UserPoolDomain diff --git a/infrastructure/environments/cloudformation/full/organisation/sso1.yaml b/infrastructure/environments/cloudformation/full/organisation/sso1.yaml index 6aec88f..d3d3159 100644 --- a/infrastructure/environments/cloudformation/full/organisation/sso1.yaml +++ b/infrastructure/environments/cloudformation/full/organisation/sso1.yaml @@ -37,24 +37,6 @@ Resources: VerificationMessageTemplate: DefaultEmailOption: CONFIRM_WITH_LINK - #CognitoUserPoolClient: - # Type: AWS::Cognito::UserPoolClient - # Properties: - # ClientName: !Sub "${ApplicationName}-${OrganisationName}-cognito-client-${EnvironmentName}" - # UserPoolId: !Ref CognitoUserPool - # GenerateSecret: true - # AllowedOAuthFlows: - # - code - # - implicit - # AllowedOAuthScopes: - # - email - # - aws.cognito.signin.user.admin - # - openid - # LogoutURLs: - # - !Ref LogoutURL - # CallbackURLs: - # - !Ref CallbackURL - UserPoolDomain: Type: AWS::Cognito::UserPoolDomain Properties: From 4f120143219aad90da1ba7666bb913bfc6eb2bb6 Mon Sep 17 00:00:00 2001 From: Matthew Pugh Date: Thu, 28 Nov 2024 16:38:52 +0000 Subject: [PATCH 2/3] Removed lambda trigger to stick with base case that's like-for-like with current setup --- .../full/common/cognito_pool_triggers.yaml | 65 --- .../full/common/general_key_access.yaml | 63 +++ .../cloudformation/full/la/frontend_ec2.yaml | 451 ------------------ 3 files changed, 63 insertions(+), 516 deletions(-) delete mode 100644 infrastructure/environments/cloudformation/full/common/cognito_pool_triggers.yaml create mode 100644 infrastructure/environments/cloudformation/full/common/general_key_access.yaml delete mode 100644 infrastructure/environments/cloudformation/full/la/frontend_ec2.yaml diff --git a/infrastructure/environments/cloudformation/full/common/cognito_pool_triggers.yaml b/infrastructure/environments/cloudformation/full/common/cognito_pool_triggers.yaml deleted file mode 100644 index 4d34d4e..0000000 --- a/infrastructure/environments/cloudformation/full/common/cognito_pool_triggers.yaml +++ /dev/null @@ -1,65 +0,0 @@ -AWSTemplateFormatVersion: 2010-09-09 -Description: | - This template adds cognito triggers to handle post-authentication tasks - - -Parameters: - DataStoreLocationArn: - Description: The S3 Bucket users will have access to for uploading files - Type: String - LambdaCodeBucket: - Description: Bucket where code is located for Lambda functions - Type: String - -Resources: - GroupAssignLambda: - Type: AWS::Lambda::Function - Properties: - Code: - S3Bucket: !Ref LambdaCodeBucket - S3Key: group-assign-lambda.zip - Role: !GetAtt GroupAssignLambdaRole.Arn - Handler: handler.lambda_handler - Runtime: python3.11 - Timeout: 60 - Environment: - Variables: - USER_POOL_ID: !Ref CognitoUserPool - GROUP_NAME: !Ref GeneralAccessGroup - ENVIRONMENT: !Ref Environment - - GeneralUserRole: - Type: AWS::IAM::Role - Properties: - RoleName: GeneralUserRole - AssumeRolePolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Principal: - Service: ec2.amazonaws.com - Action: sts:AssumeRole - Policies: - - PolicyName: GeneralUserPolicy - PolicyDocument: - Version: "2012-10-17" - Statement: - - Sid: AllowFrontendDataStoreBucketAccess - Effect: Allow - Action: - - "s3:DeleteObject" - - "s3:GetObject" - - "s3:ListBucket" - - "s3:PutObject" - - "s3:PutObjectAcl" - Resource: - - !Sub "${DataStoreLocationArn}" - - !Sub "${DataStoreLocationArn}/*" - - GeneralAccessGroup: - Type: AWS::Cognito::UserPoolGroup - Properties: - GroupName: "GeneralUserAccess" - Precedence: 0 - RoleArn: !Ref FrontendPermissionRoleARN - UserPoolId: !Ref CognitoUserPool diff --git a/infrastructure/environments/cloudformation/full/common/general_key_access.yaml b/infrastructure/environments/cloudformation/full/common/general_key_access.yaml new file mode 100644 index 0000000..e305f86 --- /dev/null +++ b/infrastructure/environments/cloudformation/full/common/general_key_access.yaml @@ -0,0 +1,63 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: | + This template adds cognito triggers to handle post-authentication tasks + + +Parameters: + DataStoreLocationArn: + Description: The S3 Bucket users will have access to for uploading files + Type: String + LambdaCodeBucket: + Description: Bucket where code is located for Lambda functions + Type: String + CognitoUserPool: + Description: ID of the User Pool to add the triggers to + Type: String + Environment: + Type: String + Description: | + Determines the type of environment. "stag" and "prod" are the two valid strings. Stag will auto-deploy + new versions, while prod will only deploy the cached versions and updates will need to be applied through + infrastructure updates. + Default: prod + +Resources: + FrontendUser: + Type: AWS::IAM::User + Properties: + UserName: "frontend-hosting-user" + + GeneralUserPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyName: GeneralUserPolicy + Users: + - !Ref FrontendUser + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - "s3:DeleteObject" + - "s3:GetObject" + - "s3:ListBucket" + - "s3:PutObject" + - "s3:PutObjectAcl" + Resource: + - !Sub "${DataStoreLocationArn}" + - !Sub "${DataStoreLocationArn}/*" + + + AccessKey: + Type: AWS::IAM::AccessKey + Properties: + UserName: + Ref: FrontendUser + +Outputs: + AccessKeyId: + Description: "AWS Access Key ID" + Value: !Ref AccessKey + SecretAccessKey: + Description: "AWS Secret Access Key" + Value: !GetAtt AccessKey.SecretAccessKey diff --git a/infrastructure/environments/cloudformation/full/la/frontend_ec2.yaml b/infrastructure/environments/cloudformation/full/la/frontend_ec2.yaml deleted file mode 100644 index 3a3aa12..0000000 --- a/infrastructure/environments/cloudformation/full/la/frontend_ec2.yaml +++ /dev/null @@ -1,451 +0,0 @@ -AWSTemplateFormatVersion: "2010-09-09" -Description: Deploy a Django Docker container on EC2 - -Parameters: - Environment: - Type: String - Default: staging - Description: The name for the environment. Expected values are dev, staging, prod - WebsiteUrl: - Type: String - Description: The URL of the la - FrontendVpcCIDR: - Type: String - Default: 10.192.50.0/16 - Description: CIDR rule to use for the front end vpc - ProjectName: - Type: String - Default: fons - Description: Name of the la. Used to name things like database, etc. - OrganisationName: - Description: The name of the organisation or la - Type: String - FrontendLaunchType: - Type: String - Default: "FARGATE" - Description: Either FARGATE or EC2 type can be used - PublicSubnet1CIDR: - Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone - Type: String - Default: 10.192.60.0/24 - PublicSubnet2CIDR: - Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone - Type: String - Default: 10.192.80.0/24 - FrontendRepoUri: - Description: The ECR or Docker Repo server to pull the image from (e.g. 840503653997.dkr.ecr.eu-west-2.amazonaws.com) - Type: String - FrontendRepoName: - Description: The ECR or Docker Repo name to pull the image from (e.g. fons-frontend-staging) - Type: String - FrontendRepoVersion: - Description: The version of the repo image to pull (e.g. latest) - Type: String - Default: "latest" - FrontendCpu: - Type: String - Default: 256 - Description: CPU to use for the Frontend - FrontendMemory: - Type: String - Default: 512 - Description: Memory to use for the Frontend - DataStoreLocation: - Type: String - Description: Location the Frontend should look to save and load uploaded and processed files - DataStoreLocationArn: - Type: String - Description: Arn of the bucket which stores the uploaded and processed files - SecretKey: - Type: String - Description: Secret Key to be used with Django setup - CognitoUserPoolId: - Type: String - Description: User Pool ID that handles SSO/Login - CognitoUserPoolArn: - Type: String - Description: User Pool Arn that handles SSO/Login - CognitoAppClientId: - Type: String - Description: The App Client Id in Cognito that links to the application - CognitoAppDomain: - Type: String - Description: The App Domain in Cognito that links to the setup. - FrontendEC2Image: - Type: String - Default: ami-06f4d01597a96dac8 #Amazon x86-64 linux is default - Description: AMI to use for application List found on EC2 Console here https://eu-west-2.console.aws.amazon.com/ec2/home?region=eu-west-2#AMICatalog - FonsSSLCertificateARN: - Type: String - Description: ARN From ACM of the SSL Certificate - DBStorageSize: - Type: Number - Default: 20 - Description: How many GB the db should be allocated for storage - DBInstanceClass: - Type: String - Default: db.serverless - Description: Type of resources for the database to use. See https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Concepts.DBInstanceClass.html#Concepts.DBInstanceClass.Types.serverless-v2 - DBEngine: - Type: String - Default: aurora-postgresql - Description: Type of database to run. Suggested postgres or aurora-postgresql - DBStorageType: - Type: String - Default: gp2 - Description: Type of storage to run the database on (standard or gp2 are the usual options) - DBName: - Type: String - Default: postgres - Description: The name to be used for the database - DBPort: - Type: String - Default: 3306 - Description: The port to use to connect to the database - DBUsername: - Type: String - Default: postgres - Description: Username to use with the database - DBMinCapacity: - Type: String - Default: 0.5 - Description: Minimum capacity is 0.5 - DBMaxCapacity: - Type: String - Default: 1 - Description: Minimum capacity is 0.5 - -Resources: - FrontendKeyPair: - Type: 'AWS::EC2::KeyPair' - Properties: - KeyName: FrontendKeyPair - - # EC2 instance - FrontendEC2Instance: - Type: AWS::EC2::Instance - Properties: - ImageId: !Ref FrontendEC2Image - InstanceType: t2.micro - KeyName: !Ref FrontendKeyPair - IamInstanceProfile: !Ref FrontendEC2InstanceProfile - UserData: - Fn::Base64: !Sub | - #!/bin/bash -xe - yum update -y - yum install -y docker - yum install -y amazon-cloudwatch-agent - service docker start - systemctl enable docker - usermod -a -G docker ec2-user - aws ecr get-login-password --region eu-west-2 | docker login --username AWS --password-stdin ${FrontendRepoUri} - docker pull ${FrontendRepoUri}/${FrontendRepoName}:${FrontendRepoVersion} - docker run -d -p 0.0.0.0:80:8000 -e AWS_REGION=${AWS::Region} \ - -e AWS_COGNITO_USER_POOL_ID=${CognitoUserPoolId} \ - -e AWS_COGNITO_APP_CLIENT_ID=${CognitoAppClientId} \ - -e AWS_COGNITO_DOMAIN=${CognitoAppDomain} \ - -e DJANGO_SECRET_KEY=${SecretKey} \ - -e SF_FS_BACKEND_URL=${DataStoreLocation} \ - ${FrontendRepoUri}/${FrontendRepoName}:${FrontendRepoVersion} - NetworkInterfaces: - - AssociatePublicIpAddress: "true" - DeviceIndex: "0" - GroupSet: - - !Ref FrontendSecurityGroup - SubnetId: !Ref FrontendPublicSubnet1 - - # Security Group - FrontendSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - GroupName: !Sub "frontend-sg-${Environment}" - GroupDescription: Enable HTTP access - VpcId: !Ref FrontendVpc - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 80 - ToPort: 80 - CidrIp: 0.0.0.0/0 # This allows HTTP traffic from anywhere - - IpProtocol: tcp - FromPort: 8000 - ToPort: 8000 - CidrIp: 0.0.0.0/0 # This allows HTTP traffic from anywhere - - IpProtocol: tcp - FromPort: 443 - ToPort: 443 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 22 - ToPort: 22 - CidrIp: 0.0.0.0/0 - - #VPC - FrontendVpc: - Type: AWS::EC2::VPC - Properties: - CidrBlock: !Ref FrontendVpcCIDR - EnableDnsSupport: true - EnableDnsHostnames: true - Tags: - - Key: Name - Value: !Ref Environment - - FrontendTargetGroup: - Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' - Properties: - Name: FrontendTargetGroup - Port: 80 - Protocol: HTTP - VpcId: !Ref FrontendVpc - TargetType: instance - Targets: - - Id: !Ref FrontendEC2Instance - - FrontendALB: - Type: AWS::ElasticLoadBalancingV2::LoadBalancer - Properties: - Name: !Sub "frontend-alb-${Environment}" - Subnets: - - !Ref FrontendPublicSubnet1 - - !Ref FrontendPublicSubnet2 - SecurityGroups: - - !Ref FrontendSecurityGroup - Scheme: internet-facing - LoadBalancerAttributes: - - Key: idle_timeout.timeout_seconds - Value: 60 - - FrontendListener: - Type: AWS::ElasticLoadBalancingV2::Listener - DependsOn: - - FrontendALB - Properties: - DefaultActions: - - RedirectConfig: - Host: "#{host}" - Path: "/#{path}" - Port: 443 - Protocol: "HTTPS" - Query: "#{query}" - StatusCode: HTTP_301 - Type: redirect - LoadBalancerArn: !Ref FrontendALB - Port: 80 - Protocol: HTTP - - FrontendHTTPSListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - ForwardConfig: - TargetGroups: - - TargetGroupArn: !Ref FrontendTargetGroup - Weight: 1 - Order: 1 - LoadBalancerArn: !Ref FrontendALB - Port: 443 - Protocol: HTTPS - SslPolicy: ELBSecurityPolicy-TLS13-1-2-2021-06 #ELBSecurityPolicy-2016-08 - Certificates: - - CertificateArn: !Ref FonsSSLCertificateARN - - FrontendRouteTable: - Type: AWS::EC2::RouteTable - Properties: - VpcId: !Ref FrontendVpc - Tags: - - Key: Name - Value: !Sub ${Environment} Frontend Routes - - FrontendRoute: - Type: AWS::EC2::Route - DependsOn: FrontendInternetGatewayAttachment - Properties: - RouteTableId: !Ref FrontendRouteTable - DestinationCidrBlock: 0.0.0.0/0 - GatewayId: !Ref FrontendInternetGateway - - PublicSubnet1RouteTableAssociation: - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - RouteTableId: !Ref FrontendRouteTable - SubnetId: !Ref FrontendPublicSubnet1 - - PublicSubnet2RouteTableAssociation: - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - RouteTableId: !Ref FrontendRouteTable - SubnetId: !Ref FrontendPublicSubnet2 - - FrontendInternetGateway: - Type: AWS::EC2::InternetGateway - Properties: - Tags: - - Key: Name - Value: !Ref Environment - - Key: Function - Value: Frontend - - FrontendInternetGatewayAttachment: - Type: AWS::EC2::VPCGatewayAttachment - Properties: - InternetGatewayId: !Ref FrontendInternetGateway - VpcId: !Ref FrontendVpc - - FrontendEIP: - Type: AWS::EC2::EIP - Properties: - Domain: vpc - - FrontendEIPAssociation: - Type: AWS::EC2::EIPAssociation - Properties: - InstanceId: !Ref FrontendEC2Instance - EIP: !Ref FrontendEIP - - FrontendPublicSubnet1: - Type: AWS::EC2::Subnet - Properties: - VpcId: !Ref FrontendVpc - AvailabilityZone: !Select [ 0, !GetAZs '' ] - CidrBlock: !Ref PublicSubnet1CIDR - MapPublicIpOnLaunch: true - Tags: - - Key: Name - Value: !Sub ${Environment} Public Subnet for Website (AZ1) - - FrontendPublicSubnet2: - Type: AWS::EC2::Subnet - Properties: - VpcId: !Ref FrontendVpc - AvailabilityZone: !Select [ 1, !GetAZs '' ] - CidrBlock: !Ref PublicSubnet2CIDR - MapPublicIpOnLaunch: true - Tags: - - Key: Name - Value: !Sub ${Environment} Public Subnet for Website (AZ1) - - # CloudWatch - # IAM Role for EC2 - FrontendEC2Role: - Type: AWS::IAM::Role - Properties: - RoleName: FrontendEC2Role - AssumeRolePolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Principal: - Service: ec2.amazonaws.com - Action: sts:AssumeRole - Policies: - - PolicyName: FrontendCloudWatchLogsPolicy - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - logs:CreateLogGroup - - logs:CreateLogStream - - logs:PutLogEvents - Resource: "*" - - PolicyName: FrontendEC2Policy - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - ec2-instance-connect:SendSSHPublicKey - Resource: - - "*" - Condition: - StringEquals: - ec2:osuser: ec2-user - - Effect: Allow - Action: - - ec2:DescribeInstances - Resource: - - "*" - - Sid: AllowEC2DataStoreBucketAccess - Effect: Allow - Action: - - "s3:DeleteObject" - - "s3:GetObject" - - "s3:ListBucket" - - "s3:PutObject" - - "s3:PutObjectAcl" - Resource: - - !Sub "${DataStoreLocationArn}" - - !Sub "${DataStoreLocationArn}/*" - - ManagedPolicyArns: - - arn:aws:iam::aws:policy/CloudWatchFullAccess - - arn:aws:iam::aws:policy/AmazonElasticContainerRegistryPublicReadOnly - - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly - - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore - - # Attach the IAM Role to the EC2 instance - FrontendEC2InstanceProfile: - Type: AWS::IAM::InstanceProfile - Properties: - Roles: - - !Ref FrontendEC2Role - - - # Database - # Database Definition - #FrontendDatabaseCluster: - # Type: 'AWS::RDS::DBCluster' - # DeletionPolicy: Delete - # Properties: - # Engine: !Ref DBEngine - # DBClusterIdentifier: !Ref DBName - # MasterUsername: !Ref DBUsername - # MasterUserPassword: !Ref DBPassword - # StorageEncrypted: true - # ServerlessV2ScalingConfiguration: - # MinCapacity: !Ref DBMinCapacity - # MaxCapacity: !Ref DBMaxCapacity - # VpcSecurityGroupIds: - # - !Ref DatabaseSecurityGroup - # DBSubnetGroupName: !Ref DatabaseSubnetGroup - # Tags: - # - Key: Project - # Value: !Ref ProjectName - # - Key: Environment - # Value: !Ref Environment - - #DagsterDatabaseInstance: - # Type: AWS::RDS::DBInstance - # Properties: - # Engine: !Ref DBEngine - # DBInstanceClass: db.serverless - # DBClusterIdentifier: !Ref DagsterDatabaseCluster - # Tags: - # - Key: Project - # Value: !Ref ProjectName - # - Key: Environment - # Value: !Ref Environment# - - #DBPassword: - # Type: AWS::SecretsManager::Secret - # Properties: - # Name: DBPassword - # GenerateSecretString: - # ExcludeLowercase: false - # ExcludeNumbers: false - # ExcludePunctuation: false - # ExcludeUppercase: false - # IncludeSpace: false - # PasswordLength: 20 - # RequireEachIncludedType: true - # ExcludeCharacters: "\"'@/\\" - -Outputs: - PublicIP: - Description: Public IP address of the EC2 instance - Value: !GetAtt FrontendEC2Instance.PublicIp - #FrontendDatabaseEndpointAddress: - # Description: Endpoint Address for the Database - # Value: !GetAtt FrontendDatabaseCluster.Endpoint.Address From 82095dd9d980ac082bd05231db25c296e4639728 Mon Sep 17 00:00:00 2001 From: Matthew Pugh Date: Thu, 28 Nov 2024 16:44:08 +0000 Subject: [PATCH 3/3] removed role lambda as unused in this iteration --- .../full/common/general_key_access.yaml | 3 - .../full/common/lambda/assign_group/README.md | 28 -- .../assign_group/assign_group/__init__.py | 0 .../assign_group/assign_group/handler.py | 41 -- .../common/lambda/assign_group/poetry.lock | 367 ------------------ .../common/lambda/assign_group/pyproject.toml | 19 - .../lambda/assign_group/tests/__init__.py | 0 .../lambda/assign_group/tests/test_handler.py | 39 -- .../cloudformation/full/la/sso1.yaml | 2 - 9 files changed, 499 deletions(-) delete mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/README.md delete mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/__init__.py delete mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/handler.py delete mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/poetry.lock delete mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/pyproject.toml delete mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/__init__.py delete mode 100644 infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/test_handler.py diff --git a/infrastructure/environments/cloudformation/full/common/general_key_access.yaml b/infrastructure/environments/cloudformation/full/common/general_key_access.yaml index e305f86..a151050 100644 --- a/infrastructure/environments/cloudformation/full/common/general_key_access.yaml +++ b/infrastructure/environments/cloudformation/full/common/general_key_access.yaml @@ -7,9 +7,6 @@ Parameters: DataStoreLocationArn: Description: The S3 Bucket users will have access to for uploading files Type: String - LambdaCodeBucket: - Description: Bucket where code is located for Lambda functions - Type: String CognitoUserPool: Description: ID of the User Pool to add the triggers to Type: String diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/README.md b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/README.md deleted file mode 100644 index 7a7b0a7..0000000 --- a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Scaling Lambda - -## Manual Process -To package this, do the following: - -1. If it doesn't exist, make the package directory -```commandline -mkdir package -``` -2. Next, we want to ensure all the libraries are present in the package: -```commandline -poetry run pip install --target ./package boto3 -``` -3. Zip Everything Up -```commandline -cd package -zip -r ../assign-group-lambda.zip -``` -4. Add the lambda function handler to the zip -```commandline -cd ../assign_group -zip ../assign-group-lambda.zip ./handler.py -``` -5. The zip should have a flat directory structure, ready to be uploaded to s3 - -## Automated Process -To do. The above process could be done via a github actions and then an upload step could push this to s3, -and redeployed to the lambda. \ No newline at end of file diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/__init__.py b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/handler.py b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/handler.py deleted file mode 100644 index e81d1c7..0000000 --- a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/assign_group/handler.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -This module assigns a user to a standard user group after they login. -""" -import logging -import boto3 - -def lambda_handler(event, context): - """ - :param event: AWS Lambda event object containing Cognito sign-in information - :param context: AWS Lambda context object - :return: Modified event with successful processing - """ - cognito_idp = boto3.client("cognito-idp") - - try: - user_pool_id = event["userPoolId"] - username = event["userName"] - except KeyError as err: - logging.error("Could not get required information from event: %s", err) - raise - - try: - cognito_idp.admin_add_user_to_group( - UserPoolId=user_pool_id, Username=username, GroupName="GeneralUserAccess" - ) - except cognito_idp.Client.exceptions.InvalidParameterException as err: - logging.error("Invalid parameter specified when assigning to group: %s", err) - except cognito_idp.Client.exceptions.ResourceNotFoundException as err: - logging.error("Can't find user pool") - except cognito_idp.Client.exceptions.TooManyRequestsException: - logging.error( - "User group assignment failed due to too many requests on the service" - ) - except cognito_idp.Client.exceptions.NotAuthorizedException: - logging.error("Don't have permission to add user to group") - except cognito_idp.Client.exceptions.UserNotFoundException: - logging.error("User not found in pool") - except Exception as err: - logging.error("An unexpected error has occurred: %s", err) - - return event diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/poetry.lock b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/poetry.lock deleted file mode 100644 index af2522f..0000000 --- a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/poetry.lock +++ /dev/null @@ -1,367 +0,0 @@ -# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. - -[[package]] -name = "astroid" -version = "3.3.5" -description = "An abstract syntax tree for Python with inference support." -optional = false -python-versions = ">=3.9.0" -files = [ - {file = "astroid-3.3.5-py3-none-any.whl", hash = "sha256:a9d1c946ada25098d790e079ba2a1b112157278f3fb7e718ae6a9252f5835dc8"}, - {file = "astroid-3.3.5.tar.gz", hash = "sha256:5cfc40ae9f68311075d27ef68a4841bdc5cc7f6cf86671b49f00607d30188e2d"}, -] - -[[package]] -name = "black" -version = "24.10.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.9" -files = [ - {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, - {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, - {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, - {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, - {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, - {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, - {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, - {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, - {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, - {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, - {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, - {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, - {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, - {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, - {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, - {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, - {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, - {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, - {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, - {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, - {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, - {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.10)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "boto3" -version = "1.35.68" -description = "The AWS SDK for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "boto3-1.35.68-py3-none-any.whl", hash = "sha256:9b26fa31901da7793c1dcd65eee9bab7e897d8aa1ffed0b5e1c3bce93d2aefe4"}, - {file = "boto3-1.35.68.tar.gz", hash = "sha256:091d6bed1422370987a839bff3f8755df7404fc15e9fac2a48e8505356f07433"}, -] - -[package.dependencies] -botocore = ">=1.35.68,<1.36.0" -jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.10.0,<0.11.0" - -[package.extras] -crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] - -[[package]] -name = "botocore" -version = "1.35.68" -description = "Low-level, data-driven core of boto 3." -optional = false -python-versions = ">=3.8" -files = [ - {file = "botocore-1.35.68-py3-none-any.whl", hash = "sha256:599139d5564291f5be873800711f9e4e14a823395ae9ce7b142be775e9849b94"}, - {file = "botocore-1.35.68.tar.gz", hash = "sha256:42c3700583a82f2b5316281a073d644a521d6358837e2b446dc458ba5d990fb4"}, -] - -[package.dependencies] -jmespath = ">=0.7.1,<2.0.0" -python-dateutil = ">=2.1,<3.0.0" -urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} - -[package.extras] -crt = ["awscrt (==0.22.0)"] - -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "dill" -version = "0.3.9" -description = "serialize all of Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, - {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, -] - -[package.extras] -graph = ["objgraph (>=1.7.2)"] -profile = ["gprof2dot (>=2022.7.29)"] - -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.7" -files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, -] - -[[package]] -name = "isort" -version = "5.13.2" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, - {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, -] - -[package.extras] -colors = ["colorama (>=0.4.6)"] - -[[package]] -name = "jmespath" -version = "1.0.1" -description = "JSON Matching Expressions" -optional = false -python-versions = ">=3.7" -files = [ - {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, - {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, -] - -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[[package]] -name = "packaging" -version = "24.2" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, - {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, -] - -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - -[[package]] -name = "platformdirs" -version = "4.3.6" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -optional = false -python-versions = ">=3.8" -files = [ - {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, - {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, -] - -[package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.11.2)"] - -[[package]] -name = "pluggy" -version = "1.5.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "pylint" -version = "3.3.1" -description = "python code static checker" -optional = false -python-versions = ">=3.9.0" -files = [ - {file = "pylint-3.3.1-py3-none-any.whl", hash = "sha256:2f846a466dd023513240bc140ad2dd73bfc080a5d85a710afdb728c420a5a2b9"}, - {file = "pylint-3.3.1.tar.gz", hash = "sha256:9f3dcc87b1203e612b78d91a896407787e708b3f189b5fa0b307712d49ff0c6e"}, -] - -[package.dependencies] -astroid = ">=3.3.4,<=3.4.0-dev0" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -dill = [ - {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, -] -isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" -mccabe = ">=0.6,<0.8" -platformdirs = ">=2.2.0" -tomlkit = ">=0.10.1" - -[package.extras] -spelling = ["pyenchant (>=3.2,<4.0)"] -testutils = ["gitpython (>3)"] - -[[package]] -name = "pytest" -version = "8.3.3" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, - {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=1.5,<2" - -[package.extras] -dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -files = [ - {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, - {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "s3transfer" -version = "0.10.4" -description = "An Amazon S3 Transfer Manager" -optional = false -python-versions = ">=3.8" -files = [ - {file = "s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e"}, - {file = "s3transfer-0.10.4.tar.gz", hash = "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7"}, -] - -[package.dependencies] -botocore = ">=1.33.2,<2.0a.0" - -[package.extras] -crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - -[[package]] -name = "tomlkit" -version = "0.13.2" -description = "Style preserving TOML library" -optional = false -python-versions = ">=3.8" -files = [ - {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, - {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, -] - -[[package]] -name = "urllib3" -version = "2.2.3" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = ">=3.8" -files = [ - {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, - {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, -] - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] - -[metadata] -lock-version = "2.0" -python-versions = "^3.11" -content-hash = "48844298edfae164532bbd8e5b417a2c075bc5bf47e30646022a37be1376ec77" diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/pyproject.toml b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/pyproject.toml deleted file mode 100644 index 3c30a0b..0000000 --- a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/pyproject.toml +++ /dev/null @@ -1,19 +0,0 @@ -[tool.poetry] -name = "assign group lambda" -version = "0.1.0" -description = "Assigns user groups to users who log into the system" -authors = ["Matthew Pugh "] -readme = "README.md" - -[tool.poetry.dependencies] -python = "^3.11" -boto3 = "^1.35.67" - -[tool.poetry.group.dev.dependencies] -pytest = "^8.3.3" -black = "^24.10.0" -pylint = "^3.3.1" - -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/__init__.py b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/test_handler.py b/infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/test_handler.py deleted file mode 100644 index 17365da..0000000 --- a/infrastructure/environments/cloudformation/full/common/lambda/assign_group/tests/test_handler.py +++ /dev/null @@ -1,39 +0,0 @@ -import unittest -from unittest.mock import patch, Mock, call, MagicMock -from assign_group.handler import lambda_handler - - -class TestLambdaHandler(unittest.TestCase): - @patch("os.environ.get") - @patch("boto3.client") - def test_lambda_handler(self, mock_boto_client, mock_get_env): - mock_idp_client = Mock() - mock_boto_client.return_value = mock_idp_client - - event = {"userPoolId": "test_pool_a890", "userName": "test.user"} - - res = lambda_handler(event, None) - - assert res == event - - mock_idp_client.admin_add_user_to_group.assert_has_calls( - [ - call( - UserPoolId=event["userPoolId"], - Username=event["userName"], - GroupName="GeneralUserAccess", - ) - ] - ) - - @patch("os.environ.get") - @patch("boto3.client") - def test_lambda_handler_missing_keys(self, mock_boto_client, mock_get_env): - mock_idp_client = Mock() - mock_boto_client.return_value = mock_idp_client - - event = {} - with self.assertRaises(KeyError) as context: - res = lambda_handler(event, None) - - mock_idp_client.admin_add_user_to_group.assert_not_called() diff --git a/infrastructure/environments/cloudformation/full/la/sso1.yaml b/infrastructure/environments/cloudformation/full/la/sso1.yaml index fa055b7..9657f11 100644 --- a/infrastructure/environments/cloudformation/full/la/sso1.yaml +++ b/infrastructure/environments/cloudformation/full/la/sso1.yaml @@ -37,8 +37,6 @@ Resources: RequireSymbols: true VerificationMessageTemplate: DefaultEmailOption: CONFIRM_WITH_LINK - LambdaConfig: - PostConfirmation: !Ref GroupAssignLambda UserPoolDomain: Type: AWS::Cognito::UserPoolDomain