diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 66975dbc2557..746228d61e9e 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -30,3 +30,5 @@ optional_value = final [bumpversion:file:internal/constants/constants.go] [bumpversion:file:web/src/common/constants.ts] + +[bumpversion:file:website/docs/install-config/install/aws/template.yaml] diff --git a/.github/workflows/ci-aws-cfn.yml b/.github/workflows/ci-aws-cfn.yml new file mode 100644 index 000000000000..59e038ef6efe --- /dev/null +++ b/.github/workflows/ci-aws-cfn.yml @@ -0,0 +1,43 @@ +name: authentik-ci-aws-cfn + +on: + push: + branches: + - main + - next + - version-* + pull_request: + branches: + - main + - version-* + +env: + POSTGRES_DB: authentik + POSTGRES_USER: authentik + POSTGRES_PASSWORD: "EK-5jnKfjrGRm<77" + +jobs: + check-changes-applied: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup authentik env + uses: ./.github/actions/setup + - uses: actions/setup-node@v4 + with: + node-version-file: website/package.json + cache: "npm" + cache-dependency-path: website/package-lock.json + - working-directory: website/ + run: | + npm ci + - name: Check changes have been applied + run: | + poetry run make aws-cfn + git diff --exit-code + ci-aws-cfn-mark: + needs: + - check-changes-applied + runs-on: ubuntu-latest + steps: + - run: echo mark diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml index c0b2d66c277e..cc001d66d9bd 100644 --- a/.github/workflows/release-publish.yml +++ b/.github/workflows/release-publish.yml @@ -169,6 +169,27 @@ jobs: file: ./authentik-outpost-${{ matrix.type }}_${{ matrix.goos }}_${{ matrix.goarch }} asset_name: authentik-outpost-${{ matrix.type }}_${{ matrix.goos }}_${{ matrix.goarch }} tag: ${{ github.ref }} + upload-aws-cfn-template: + permissions: + # Needed for AWS login + id-token: write + contents: read + needs: + - build-server + - build-outpost + env: + AWS_REGION: eu-central-1 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: "arn:aws:iam::016170277896:role/github_goauthentik_authentik" + aws-region: ${{ env.AWS_REGION }} + - name: Upload template + run: | + aws s3 cp website/docs/install-config/install/aws/template.yaml s3://authentik-cloudformation-templates/authentik.ecs.${{ github.ref }}.yaml + aws s3 cp website/docs/install-config/install/aws/template.yaml s3://authentik-cloudformation-templates/authentik.ecs.latest.yaml test-release: needs: - build-server diff --git a/Makefile b/Makefile index 277139e32148..ab45437e7c15 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ PWD = $(shell pwd) UID = $(shell id -u) GID = $(shell id -g) NPM_VERSION = $(shell python -m scripts.npm_version) -PY_SOURCES = authentik tests scripts lifecycle .github +PY_SOURCES = authentik tests scripts lifecycle .github website/docs/install-config/install/aws DOCKER_IMAGE ?= "authentik:test" GEN_API_TS = "gen-ts-api" @@ -252,6 +252,9 @@ website-build: website-watch: ## Build and watch the documentation website, updating automatically cd website && npm run watch +aws-cfn: + cd website && npm run aws-cfn + ######################### ## Docker ######################### diff --git a/poetry.lock b/poetry.lock index b4a7fa5b0d52..23b386c92c45 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -342,6 +342,91 @@ six = "*" [package.extras] visualize = ["Twisted (>=16.1.1)", "graphviz (>0.5.1)"] +[[package]] +name = "aws-cdk-asset-awscli-v1" +version = "2.2.212" +description = "A library that contains the AWS CLI for use in Lambda Layers" +optional = false +python-versions = "~=3.8" +files = [ + {file = "aws_cdk.asset_awscli_v1-2.2.212-py3-none-any.whl", hash = "sha256:12161e2d528698957bc2c0f53d2f5e81de54f8ad0e4b94316634bdc1db50f539"}, + {file = "aws_cdk_asset_awscli_v1-2.2.212.tar.gz", hash = "sha256:3a4374562f37c9cd3f59cb45173a18ef0f781c0f1df187773662a1dd14cc18fd"}, +] + +[package.dependencies] +jsii = ">=1.105.0,<2.0.0" +publication = ">=0.0.3" +typeguard = ">=2.13.3,<4.3.0" + +[[package]] +name = "aws-cdk-asset-kubectl-v20" +version = "2.1.3" +description = "A Lambda Layer that contains kubectl v1.20" +optional = false +python-versions = "~=3.8" +files = [ + {file = "aws_cdk.asset_kubectl_v20-2.1.3-py3-none-any.whl", hash = "sha256:d5612e5bd03c215a28ce53193b1144ecf4e93b3b6779563c046a8a74d83a3979"}, + {file = "aws_cdk_asset_kubectl_v20-2.1.3.tar.gz", hash = "sha256:237cd8530d9e8be0bbc7159af927dbb6b7f91bf3f4099c8ef4d9a213b34264be"}, +] + +[package.dependencies] +jsii = ">=1.103.1,<2.0.0" +publication = ">=0.0.3" +typeguard = ">=2.13.3,<5.0.0" + +[[package]] +name = "aws-cdk-asset-node-proxy-agent-v6" +version = "2.1.0" +description = "@aws-cdk/asset-node-proxy-agent-v6" +optional = false +python-versions = "~=3.8" +files = [ + {file = "aws_cdk.asset_node_proxy_agent_v6-2.1.0-py3-none-any.whl", hash = "sha256:24a388b69a44d03bae6dbf864c4e25ba650d4b61c008b4568b94ffbb9a69e40e"}, + {file = "aws_cdk_asset_node_proxy_agent_v6-2.1.0.tar.gz", hash = "sha256:1f292c0631f86708ba4ee328b3a2b229f7e46ea1c79fbde567ee9eb119c2b0e2"}, +] + +[package.dependencies] +jsii = ">=1.103.1,<2.0.0" +publication = ">=0.0.3" +typeguard = ">=2.13.3,<5.0.0" + +[[package]] +name = "aws-cdk-cloud-assembly-schema" +version = "38.0.1" +description = "Cloud Assembly Schema" +optional = false +python-versions = "~=3.8" +files = [ + {file = "aws_cdk.cloud_assembly_schema-38.0.1-py3-none-any.whl", hash = "sha256:92613b46213b460681e9424f09b77f06ff059eb1c773092540364ef82fcecf55"}, + {file = "aws_cdk_cloud_assembly_schema-38.0.1.tar.gz", hash = "sha256:7c75861adc41f7b959910d4b3b191ea242815402e599dbfa31934892838ae25e"}, +] + +[package.dependencies] +jsii = ">=1.103.1,<2.0.0" +publication = ">=0.0.3" +typeguard = ">=2.13.3,<5.0.0" + +[[package]] +name = "aws-cdk-lib" +version = "2.167.1" +description = "Version 2 of the AWS Cloud Development Kit library" +optional = false +python-versions = "~=3.8" +files = [ + {file = "aws_cdk_lib-2.167.1-py3-none-any.whl", hash = "sha256:a40d53a0ad0cd911a0755f56e980a19db5cba046a4d0e9e4a9a9a02c4b2e4f71"}, + {file = "aws_cdk_lib-2.167.1.tar.gz", hash = "sha256:fa4c2a0ae6980c0e4ee67abe0597e6ea368ede111f57412005a53f129e6db503"}, +] + +[package.dependencies] +"aws-cdk.asset-awscli-v1" = ">=2.2.208,<3.0.0" +"aws-cdk.asset-kubectl-v20" = ">=2.1.3,<3.0.0" +"aws-cdk.asset-node-proxy-agent-v6" = ">=2.1.0,<3.0.0" +"aws-cdk.cloud-assembly-schema" = ">=38.0.1,<39.0.0" +constructs = ">=10.0.0,<11.0.0" +jsii = ">=1.104.0,<2.0.0" +publication = ">=0.0.3" +typeguard = ">=2.13.3,<4.3.0" + [[package]] name = "azure-core" version = "1.30.2" @@ -558,6 +643,30 @@ files = [ {file = "cachetools-5.4.0.tar.gz", hash = "sha256:b8adc2e7c07f105ced7bc56dbb6dfbe7c4a00acce20e2227b3f355be89bc6827"}, ] +[[package]] +name = "cattrs" +version = "24.1.2" +description = "Composable complex class support for attrs and dataclasses." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cattrs-24.1.2-py3-none-any.whl", hash = "sha256:67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0"}, + {file = "cattrs-24.1.2.tar.gz", hash = "sha256:8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85"}, +] + +[package.dependencies] +attrs = ">=23.1.0" + +[package.extras] +bson = ["pymongo (>=4.4.0)"] +cbor2 = ["cbor2 (>=5.4.6)"] +msgpack = ["msgpack (>=1.0.5)"] +msgspec = ["msgspec (>=0.18.5)"] +orjson = ["orjson (>=3.9.2)"] +pyyaml = ["pyyaml (>=6.0)"] +tomlkit = ["tomlkit (>=0.11.8)"] +ujson = ["ujson (>=5.7.0)"] + [[package]] name = "cbor2" version = "5.6.5" @@ -989,6 +1098,22 @@ files = [ {file = "constantly-23.10.4.tar.gz", hash = "sha256:aa92b70a33e2ac0bb33cd745eb61776594dc48764b06c35e0efd050b7f1c7cbd"}, ] +[[package]] +name = "constructs" +version = "10.4.2" +description = "A programming model for software-defined state" +optional = false +python-versions = "~=3.8" +files = [ + {file = "constructs-10.4.2-py3-none-any.whl", hash = "sha256:1f0f59b004edebfde0f826340698b8c34611f57848139b7954904c61645f13c1"}, + {file = "constructs-10.4.2.tar.gz", hash = "sha256:ce54724360fffe10bab27d8a081844eb81f5ace7d7c62c84b719c49f164d5307"}, +] + +[package.dependencies] +jsii = ">=1.102.0,<2.0.0" +publication = ">=0.0.3" +typeguard = ">=2.13.3,<2.14.0" + [[package]] name = "coverage" version = "7.6.8" @@ -2235,6 +2360,26 @@ files = [ {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, ] +[[package]] +name = "jsii" +version = "1.105.0" +description = "Python client for jsii runtime" +optional = false +python-versions = "~=3.8" +files = [ + {file = "jsii-1.105.0-py3-none-any.whl", hash = "sha256:8888088479b449db6d8e3a7df25434ec4580bf4fc13f4f952e9db5f2a3fc0c0f"}, + {file = "jsii-1.105.0.tar.gz", hash = "sha256:435682d509e628e6f8a765b017102e6fcd553f4d0f6b3417b3f7eb295c2e0d1f"}, +] + +[package.dependencies] +attrs = ">=21.2,<25.0" +cattrs = ">=1.8,<24.2" +importlib-resources = ">=5.2.0" +publication = ">=0.0.3" +python-dateutil = "*" +typeguard = ">=2.13.3,<4.5.0" +typing-extensions = ">=3.8,<5.0" + [[package]] name = "jsonpatch" version = "1.33" @@ -3689,6 +3834,17 @@ files = [ {file = "psycopg_c-3.2.3.tar.gz", hash = "sha256:06ae7db8eaec1a3845960fa7f997f4ccdb1a7a7ab8dc593a680bcc74e1359671"}, ] +[[package]] +name = "publication" +version = "0.0.3" +description = "Publication helps you maintain public-api-friendly modules by preventing unintentional access to private implementation details via introspection." +optional = false +python-versions = "*" +files = [ + {file = "publication-0.0.3-py2.py3-none-any.whl", hash = "sha256:0248885351febc11d8a1098d5c8e3ab2dabcf3e8c0c96db1e17ecd12b53afbe6"}, + {file = "publication-0.0.3.tar.gz", hash = "sha256:68416a0de76dddcdd2930d1c8ef853a743cc96c82416c4e4d3b5d901c6276dc4"}, +] + [[package]] name = "pyasn1" version = "0.6.0" @@ -5002,6 +5158,21 @@ all = ["twisted (>=20.3.0)", "zope.interface (>=5.2.0)"] dev = ["pep8 (>=1.6.2)", "pyenchant (>=1.6.6)", "pytest (>=2.6.4)", "pytest-cov (>=1.8.1)", "sphinx (>=1.2.3)", "sphinx-rtd-theme (>=0.1.9)", "sphinxcontrib-spelling (>=2.1.2)", "tox (>=2.1.1)", "tox-gh-actions (>=2.2.0)", "twine (>=1.6.5)", "wheel"] twisted = ["twisted (>=20.3.0)", "zope.interface (>=5.2.0)"] +[[package]] +name = "typeguard" +version = "2.13.3" +description = "Run-time type checker for Python" +optional = false +python-versions = ">=3.5.3" +files = [ + {file = "typeguard-2.13.3-py3-none-any.whl", hash = "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1"}, + {file = "typeguard-2.13.3.tar.gz", hash = "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4"}, +] + +[package.extras] +doc = ["sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["mypy", "pytest", "typing-extensions"] + [[package]] name = "typing-extensions" version = "4.12.2" @@ -5744,4 +5915,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "~3.12" -content-hash = "2a7712ca513371eb16ff0b87fc80218e982a5a734bba0bb130b8123e807eb16f" +content-hash = "5eeade864b7e0a67809e77ae4a74e1a164990554f49b3f2a2f87941c5a5be737" diff --git a/pyproject.toml b/pyproject.toml index af41e1f81c55..7dc177bc8879 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -153,12 +153,14 @@ xmlsec = "*" zxcvbn = "*" [tool.poetry.dev-dependencies] +aws-cdk-lib = "*" bandit = "*" black = "*" bump2version = "*" channels = { version = "*", extras = ["daphne"] } codespell = "*" colorama = "*" +constructs = "*" coverage = { extras = ["toml"], version = "*" } debugpy = "*" drf-jsonschema-serializer = "*" diff --git a/website/.prettierignore b/website/.prettierignore index 4b64495ddc30..b23d45546379 100644 --- a/website/.prettierignore +++ b/website/.prettierignore @@ -5,3 +5,5 @@ coverage node_modules help static +docs/install-config/install/aws/template.yaml +docs/install-config/install/aws/cdk.out diff --git a/website/docs/install-config/install/aws/.gitignore b/website/docs/install-config/install/aws/.gitignore new file mode 100644 index 000000000000..b5b74b15f3e9 --- /dev/null +++ b/website/docs/install-config/install/aws/.gitignore @@ -0,0 +1 @@ +cdk.out diff --git a/website/docs/install-config/install/aws/app.py b/website/docs/install-config/install/aws/app.py new file mode 100755 index 000000000000..59ae18916cca --- /dev/null +++ b/website/docs/install-config/install/aws/app.py @@ -0,0 +1,421 @@ +#!/usr/bin/env python3 + +import json + +from aws_cdk import ( + App, + CfnOutput, + CfnParameter, + Duration, + RemovalPolicy, + Stack, +) +from aws_cdk import ( + aws_ec2 as ec2, +) +from aws_cdk import ( + aws_ecs as ecs, +) +from aws_cdk import ( + aws_efs as efs, +) +from aws_cdk import ( + aws_elasticache as elasticache, +) +from aws_cdk import ( + aws_elasticloadbalancingv2 as elbv2, +) +from aws_cdk import ( + aws_rds as rds, +) +from aws_cdk import ( + aws_secretsmanager as secretsmanager, +) +from constructs import Construct + +from authentik import __version__ + + +class AuthentikStack(Stack): + def __init__(self, scope: Construct, id: str, **kwargs): + super().__init__(scope, id, *kwargs) + + ### Inputs + + db_instance_type = CfnParameter( + self, + "DBInstanceType", + type="String", + default="m5.large", + description="RDS PostgreSQL instance type (without the leading db.)", + ) + db_version = CfnParameter( + self, "DBVersion", type="String", default="17.1", description="RDS PostgreSQL version" + ) + db_storage = CfnParameter( + self, + "DBStorage", + type="Number", + default=10, + min_value=10, + description="RDS PostgreSQL storage size in GB", + ) + + redis_instance_type = CfnParameter( + self, + "RedisInstanceType", + type="String", + default="cache.t4g.medium", + description="ElastiCache Redis instance type (with the leading cache.)", + ) + redis_version = CfnParameter( + self, + "RedisVersion", + type="String", + default="7.1", + description="ElastiCache Redis version", + ) + + authentik_image = CfnParameter( + self, + "AuthentikImage", + type="String", + default="ghcr.io/goauthentik/server", + description="authentik Docker image", + ) + authentik_version = CfnParameter( + self, + "AuthentikVersion", + type="String", + default=__version__, + description="authentik Docker image tag", + ) + + server_cpu = CfnParameter( + self, + "AuthentikServerCPU", + type="Number", + default=512, + description="authentik server CPU units (1024 = 1 vCPU)", + ) + server_memory = CfnParameter( + self, + "AuthentikServerMemory", + type="Number", + default=1024, + description="authentik server memory in MiB", + ) + server_desired_count = CfnParameter( + self, + "AuthentikServerDesiredCount", + type="Number", + default=2, + min_value=1, + description="Desired number of authentik server tasks", + ) + + worker_cpu = CfnParameter( + self, + "AuthentikWorkerCPU", + type="Number", + default=512, + description="authentik worker CPU units (1024 = 1 vCPU)", + ) + worker_memory = CfnParameter( + self, + "AuthentikWorkerMemory", + type="Number", + default=1024, + description="authentik worker memory in MiB", + ) + worker_desired_count = CfnParameter( + self, + "AuthentikWorkerDesiredCount", + type="Number", + default=2, + min_value=1, + description="Desired number of authentik worker tasks", + ) + + certificate_arn = CfnParameter( + self, + "CertificateARN", + type="String", + description="ACM certificate ARN for HTTPS access", + ) + + ### Resources + + # VPC + + vpc = ec2.Vpc(self, "AuthentikVpc", max_azs=2, nat_gateways=1) + + # Security Groups + + db_security_group = ec2.SecurityGroup( + self, "DatabaseSG", vpc=vpc, description="Security Group for authentik RDS PostgreSQL" + ) + redis_security_group = ec2.SecurityGroup( + self, "RedisSG", vpc=vpc, description="Security Group for authentik ElastiCache Redis" + ) + authentik_security_group = ec2.SecurityGroup( + self, "AuthentikSG", vpc=vpc, description="Security Group for authentik services" + ) + db_security_group.add_ingress_rule( + peer=authentik_security_group, + connection=ec2.Port.tcp(5432), + description="Allow authentik to connect to RDS PostgreSQL", + ) + redis_security_group.add_ingress_rule( + peer=authentik_security_group, + connection=ec2.Port.tcp(6379), + description="Allow authentik to connect to ElastiCache Redis", + ) + + # Generated secrets + + db_password = secretsmanager.Secret( + self, + "DBPassword", + generate_secret_string=secretsmanager.SecretStringGenerator( + secret_string_template=json.dumps({"username": "authentik"}), + generate_string_key="password", + password_length=64, + exclude_characters='"@/\\', + ), + ) + secret_key = secretsmanager.Secret( + self, + "AuthentikSecretKey", + generate_secret_string=secretsmanager.SecretStringGenerator( + password_length=64, exclude_characters='"@/\\' + ), + ) + + # Database + + database = rds.DatabaseInstance( + self, + "AuthentikDB", + engine=rds.DatabaseInstanceEngine.postgres( + version=rds.PostgresEngineVersion.of(db_version.value_as_string, ""), + ), + instance_type=ec2.InstanceType(db_instance_type.value_as_string), + vpc=vpc, + vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS), + allocated_storage=db_storage.value_as_number, + security_groups=[db_security_group], + database_name="authentik", + credentials=rds.Credentials.from_secret(db_password), + multi_az=True, + removal_policy=RemovalPolicy.SNAPSHOT, + ) + + # Redis + + redis_subnet_group = elasticache.CfnSubnetGroup( + self, + "AuthentikRedisSubnetGroup", + subnet_ids=vpc.select_subnets( + subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS + ).subnet_ids, + description="Subnet group for authentik ElastiCache Redis", + ) + + redis = elasticache.CfnReplicationGroup( + self, + "AuthentikRedis", + replication_group_description="Redis cluster for authentik", + engine="redis", + engine_version=redis_version.value_as_string, + cache_node_type=redis_instance_type.value_as_string, + num_cache_clusters=2, + automatic_failover_enabled=True, + security_group_ids=[redis_security_group.security_group_id], + cache_subnet_group_name=redis_subnet_group.ref, + ) + + # Storage + + media_fs = efs.FileSystem( + self, + "AuthentikMediaEFS", + vpc=vpc, + removal_policy=RemovalPolicy.RETAIN, + security_group=ec2.SecurityGroup( + self, + "AuthentikMediaEFSSecurityGroup", + vpc=vpc, + description="Security group for authentik media EFS", + allow_all_outbound=True, + ), + encrypted=True, + performance_mode=efs.PerformanceMode.GENERAL_PURPOSE, + throughput_mode=efs.ThroughputMode.BURSTING, + ) + media_fs.connections.allow_default_port_from(authentik_security_group) + + media_access_point = media_fs.add_access_point( + "AuthentikMediaAccessPoint", + path="/media", + create_acl=efs.Acl(owner_uid="1000", owner_gid="1000", permissions="755"), + posix_user=efs.PosixUser(uid="1000", gid="1000"), + ) + + # ECS Cluster + + cluster = ecs.Cluster(self, "AuthentikCluster", vpc=vpc) + + environment = { + "AUTHENTIK_POSTGRESQL__HOST": database.instance_endpoint.hostname, + "AUTHENTIK_POSTGRESQL__USER": "authentik", + "AUTHENTIK_REDIS__HOST": redis.attr_primary_end_point_address, + } + + secrets = { + "AUTHENTIK_POSTGRESQL__PASSWORD": ecs.Secret.from_secrets_manager( + db_password, field="password" + ), + "AUTHENTIK_SECRET_KEY": ecs.Secret.from_secrets_manager(secret_key), + } + + server_task = ecs.FargateTaskDefinition( + self, + "AuthentikServerTask", + cpu=server_cpu.value_as_number, + memory_limit_mib=server_memory.value_as_number, + ) + server_task.add_volume( + name="media", + efs_volume_configuration=ecs.EfsVolumeConfiguration( + file_system_id=media_fs.file_system_id, + transit_encryption="ENABLED", + authorization_config=ecs.AuthorizationConfig( + access_point_id=media_access_point.access_point_id, + iam="ENABLED", + ), + ), + ) + server_container = server_task.add_container( + "AuthentikServerContainer", + image=ecs.ContainerImage.from_registry( + f"{authentik_image.value_as_string}:{authentik_version.value_as_string}" + ), + command=["server"], + environment=environment, + secrets=secrets, + logging=ecs.LogDriver.aws_logs(stream_prefix="authentik-server"), + enable_restart_policy=True, + health_check=ecs.HealthCheck( + command=["CMD", "ak", "healthcheck"], + interval=Duration.seconds(30), + retries=3, + start_period=Duration.seconds(60), + timeout=Duration.seconds(30), + ), + ) + server_container.add_port_mappings(ecs.PortMapping(container_port=9000)) + server_container.add_mount_points( + ecs.MountPoint(container_path="/media", source_volume="media", read_only=False) + ) + server_service = ecs.FargateService( + self, + "AuthentikServerService", + cluster=cluster, + task_definition=server_task, + desired_count=server_desired_count.value_as_number, + security_groups=[authentik_security_group], + vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS), + enable_execute_command=True, + ) + + worker_task = ecs.FargateTaskDefinition( + self, + "AuthentikWorkerTask", + cpu=worker_cpu.value_as_number, + memory_limit_mib=worker_memory.value_as_number, + ) + worker_task.add_volume( + name="media", + efs_volume_configuration=ecs.EfsVolumeConfiguration( + file_system_id=media_fs.file_system_id, + transit_encryption="ENABLED", + authorization_config=ecs.AuthorizationConfig( + access_point_id=media_access_point.access_point_id, + iam="ENABLED", + ), + ), + ) + worker_container = worker_task.add_container( + "AuthentikWorkerContainer", + image=ecs.ContainerImage.from_registry( + f"{authentik_image.value_as_string}:{authentik_version.value_as_string}" + ), + command=["worker"], + environment=environment, + secrets=secrets, + logging=ecs.LogDriver.aws_logs(stream_prefix="authentik-worker"), + enable_restart_policy=True, + health_check=ecs.HealthCheck( + command=["CMD", "ak", "healthcheck"], + interval=Duration.seconds(30), + retries=3, + start_period=Duration.seconds(60), + timeout=Duration.seconds(30), + ), + ) + worker_container.add_mount_points( + ecs.MountPoint(container_path="/media", source_volume="media", read_only=False) + ) + worker_service = ecs.FargateService( # noqa: F841 + self, + "AuthentikWorkerService", + cluster=cluster, + task_definition=worker_task, + desired_count=worker_desired_count.value_as_number, + security_groups=[authentik_security_group], + vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS), + enable_execute_command=True, + ) + + # Load balancer + + lb = elbv2.ApplicationLoadBalancer( + self, + "AuthentikALB", + vpc=vpc, + internet_facing=True, + ) + https_redirect = lb.add_listener( # noqa: F841 + "AuthentikHttpListener", + port=80, + default_action=elbv2.ListenerAction.redirect(permanent=True, protocol="HTTPS"), + ) + listener = lb.add_listener( + "AuthentikHttpsListener", + port=443, + certificates=[ + elbv2.ListenerCertificate(certificate_arn=certificate_arn.value_as_string) + ], + ) + target_group = listener.add_targets( # noqa: F841 + "AuthentikServerTarget", + protocol=elbv2.ApplicationProtocol.HTTP, + port=9000, + targets=[server_service], + health_check=elbv2.HealthCheck( + path="/-/health/live/", + healthy_http_codes="200", + ), + ) + + CfnOutput( + self, + "LoadBalancerDNS", + value=lb.load_balancer_dns_name, + ) + + +app = App() +AuthentikStack(app, "AuthentikStack") +app.synth() diff --git a/website/docs/install-config/install/aws/cdk.json b/website/docs/install-config/install/aws/cdk.json new file mode 100644 index 000000000000..ddc8a5a0154b --- /dev/null +++ b/website/docs/install-config/install/aws/cdk.json @@ -0,0 +1,3 @@ +{ + "app": "./app.py" +} diff --git a/website/docs/install-config/install/aws/fix_template.py b/website/docs/install-config/install/aws/fix_template.py new file mode 100755 index 000000000000..fcdbc565ab2d --- /dev/null +++ b/website/docs/install-config/install/aws/fix_template.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 + +import yaml + +with open("template.yaml") as file: + template = yaml.safe_load(file) + del template["Conditions"]["CDKMetadataAvailable"] + del template["Parameters"]["BootstrapVersion"] + del template["Resources"]["CDKMetadata"] +with open("template.yaml", "w") as file: + yaml.dump(template, file) diff --git a/website/docs/install-config/install/aws/index.md b/website/docs/install-config/install/aws/index.md new file mode 100644 index 000000000000..48c949adff99 --- /dev/null +++ b/website/docs/install-config/install/aws/index.md @@ -0,0 +1,34 @@ +--- +title: AWS installation +--- + +You can install authentik to run on AWS with a CloudFormation template. + +### Prerequisites + +- An AWS account. +- An [AWS Certificate Manager](https://aws.amazon.com/certificate-manager/) certificate. Take note of the ARN of the certificate. + +### Installation + +Log in to your AWS account and create a CloudFormation stack [with our template](https://console.aws.amazon.com/cloudformation/home#/stacks/create/review?stackName=authentik&templateURL=https://authentik-cloudformation-templates.s3.amazonaws.com/authentik.ecs.latest.yaml). + +Under the **Certificate ARN** input, enter the previously created certificate ARN. You can also configure other settings if needed. You can follow the prompts to create the stack. + +This stack will create the following resources: + +- AWS SSM secrets for the PostgreSQL user and the authentik secret key +- A VPC for all other resources +- A RDS PostgreSQL Multi-AZ cluster +- An ElastiCache Redis Multi-AZ cluster +- An ECS cluster with two tasks: + - One for the authentik server + - One for the authentik worker +- An ALB (Application Load Balancer) pointing to the authentik server ECS task with the configured certificate +- An EFS filesystem mounted on both ECS tasks for media file storage + +The stack will output the endpoint of the ALB that to which you can point your DNS records. + +### Further customization + +If you require further customization, we recommend you install authentik via [Docker Compose](../docker-compose.mdx) or [Kubernetes](../kubernetes.md). diff --git a/website/docs/install-config/install/aws/template.yaml b/website/docs/install-config/install/aws/template.yaml new file mode 100644 index 000000000000..97fce6793792 --- /dev/null +++ b/website/docs/install-config/install/aws/template.yaml @@ -0,0 +1,1144 @@ +Conditions: {} +Outputs: + LoadBalancerDNS: + Value: + Fn::GetAtt: + - AuthentikALB992EAB01 + - DNSName +Parameters: + AuthentikImage: + Default: ghcr.io/goauthentik/server + Description: authentik Docker image + Type: String + AuthentikServerCPU: + Default: 512 + Description: authentik server CPU units (1024 = 1 vCPU) + Type: Number + AuthentikServerDesiredCount: + Default: 2 + Description: Desired number of authentik server tasks + MinValue: 1 + Type: Number + AuthentikServerMemory: + Default: 1024 + Description: authentik server memory in MiB + Type: Number + AuthentikVersion: + Default: 2024.10.4 + Description: authentik Docker image tag + Type: String + AuthentikWorkerCPU: + Default: 512 + Description: authentik worker CPU units (1024 = 1 vCPU) + Type: Number + AuthentikWorkerDesiredCount: + Default: 2 + Description: Desired number of authentik worker tasks + MinValue: 1 + Type: Number + AuthentikWorkerMemory: + Default: 1024 + Description: authentik worker memory in MiB + Type: Number + CertificateARN: + Description: ACM certificate ARN for HTTPS access + Type: String + DBInstanceType: + Default: m5.large + Description: RDS PostgreSQL instance type (without the leading db.) + Type: String + DBStorage: + Default: 10 + Description: RDS PostgreSQL storage size in GB + MinValue: 10 + Type: Number + DBVersion: + Default: '17.1' + Description: RDS PostgreSQL version + Type: String + RedisInstanceType: + Default: cache.t4g.medium + Description: ElastiCache Redis instance type (with the leading cache.) + Type: String + RedisVersion: + Default: '7.1' + Description: ElastiCache Redis version + Type: String +Resources: + AuthentikALB992EAB01: + DependsOn: + - AuthentikVpcPublicSubnet1DefaultRoute90C4189A + - AuthentikVpcPublicSubnet1RouteTableAssociation33E57E0C + - AuthentikVpcPublicSubnet2DefaultRoute2E9B0EBA + - AuthentikVpcPublicSubnet2RouteTableAssociationDA2BDD26 + Metadata: + aws:cdk:path: AuthentikStack/AuthentikALB/Resource + Properties: + LoadBalancerAttributes: + - Key: deletion_protection.enabled + Value: 'false' + Scheme: internet-facing + SecurityGroups: + - Fn::GetAtt: + - AuthentikALBSecurityGroup2B18FEEF + - GroupId + Subnets: + - Ref: AuthentikVpcPublicSubnet1Subnet0C75862A + - Ref: AuthentikVpcPublicSubnet2Subnet4DFAFA5B + Type: application + Type: AWS::ElasticLoadBalancingV2::LoadBalancer + AuthentikALBAuthentikHttpListener6825393B: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikALB/AuthentikHttpListener/Resource + Properties: + DefaultActions: + - RedirectConfig: + Protocol: HTTPS + StatusCode: HTTP_301 + Type: redirect + LoadBalancerArn: + Ref: AuthentikALB992EAB01 + Port: 80 + Protocol: HTTP + Type: AWS::ElasticLoadBalancingV2::Listener + AuthentikALBAuthentikHttpsListener34A9BF12: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikALB/AuthentikHttpsListener/Resource + Properties: + Certificates: + - CertificateArn: + Ref: CertificateARN + DefaultActions: + - TargetGroupArn: + Ref: AuthentikALBAuthentikHttpsListenerAuthentikServerTargetGroup345C3479 + Type: forward + LoadBalancerArn: + Ref: AuthentikALB992EAB01 + Port: 443 + Protocol: HTTPS + Type: AWS::ElasticLoadBalancingV2::Listener + AuthentikALBAuthentikHttpsListenerAuthentikServerTargetGroup345C3479: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikALB/AuthentikHttpsListener/AuthentikServerTargetGroup/Resource + Properties: + HealthCheckPath: /-/health/live/ + Matcher: + HttpCode: '200' + Port: 9000 + Protocol: HTTP + TargetGroupAttributes: + - Key: stickiness.enabled + Value: 'false' + TargetType: ip + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::ElasticLoadBalancingV2::TargetGroup + AuthentikALBSecurityGroup2B18FEEF: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikALB/SecurityGroup/Resource + Properties: + GroupDescription: Automatically created Security Group for ELB AuthentikStackAuthentikALB07C6B2CD + SecurityGroupIngress: + - CidrIp: 0.0.0.0/0 + Description: Allow from anyone on port 80 + FromPort: 80 + IpProtocol: tcp + ToPort: 80 + - CidrIp: 0.0.0.0/0 + Description: Allow from anyone on port 443 + FromPort: 443 + IpProtocol: tcp + ToPort: 443 + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::SecurityGroup + AuthentikALBSecurityGrouptoAuthentikStackAuthentikSG23C19B2890000F200B23: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikALB/SecurityGroup/to AuthentikStackAuthentikSG23C19B28:9000 + Properties: + Description: Load balancer to target + DestinationSecurityGroupId: + Fn::GetAtt: + - AuthentikSG3040E46F + - GroupId + FromPort: 9000 + GroupId: + Fn::GetAtt: + - AuthentikALBSecurityGroup2B18FEEF + - GroupId + IpProtocol: tcp + ToPort: 9000 + Type: AWS::EC2::SecurityGroupEgress + AuthentikCluster54E596EF: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikCluster/Resource + Type: AWS::ECS::Cluster + AuthentikDB6710DB92: + DeletionPolicy: Snapshot + Metadata: + aws:cdk:path: AuthentikStack/AuthentikDB/Resource + Properties: + AllocatedStorage: + Ref: DBStorage + CopyTagsToSnapshot: true + DBInstanceClass: + Fn::Join: + - '' + - - db. + - Ref: DBInstanceType + DBName: authentik + DBSubnetGroupName: + Ref: AuthentikDBSubnetGroup03A9E1C9 + Engine: postgres + EngineVersion: + Ref: DBVersion + MasterUserPassword: + Fn::Join: + - '' + - - '{{resolve:secretsmanager:' + - Ref: DBPassword67313E91 + - :SecretString:password::}} + MasterUsername: + Fn::Join: + - '' + - - '{{resolve:secretsmanager:' + - Ref: DBPassword67313E91 + - :SecretString:username::}} + MultiAZ: true + PubliclyAccessible: false + StorageType: gp2 + VPCSecurityGroups: + - Fn::GetAtt: + - DatabaseSG2A23C222 + - GroupId + Type: AWS::RDS::DBInstance + UpdateReplacePolicy: Snapshot + AuthentikDBSubnetGroup03A9E1C9: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikDB/SubnetGroup/Default + Properties: + DBSubnetGroupDescription: Subnet group for AuthentikDB database + SubnetIds: + - Ref: AuthentikVpcPrivateSubnet1Subnet6748EEA3 + - Ref: AuthentikVpcPrivateSubnet2Subnet6B8E7123 + Type: AWS::RDS::DBSubnetGroup + AuthentikMediaEFS4AB06689: + DeletionPolicy: Retain + Metadata: + aws:cdk:path: AuthentikStack/AuthentikMediaEFS/Resource + Properties: + Encrypted: true + FileSystemTags: + - Key: Name + Value: AuthentikStack/AuthentikMediaEFS + PerformanceMode: generalPurpose + ThroughputMode: bursting + Type: AWS::EFS::FileSystem + UpdateReplacePolicy: Retain + AuthentikMediaEFSAuthentikMediaAccessPointA60D3CC7: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikMediaEFS/AuthentikMediaAccessPoint/Resource + Properties: + AccessPointTags: + - Key: Name + Value: AuthentikStack/AuthentikMediaEFS/AuthentikMediaAccessPoint + FileSystemId: + Ref: AuthentikMediaEFS4AB06689 + PosixUser: + Gid: '1000' + Uid: '1000' + RootDirectory: + CreationInfo: + OwnerGid: '1000' + OwnerUid: '1000' + Permissions: '755' + Path: /media + Type: AWS::EFS::AccessPoint + AuthentikMediaEFSEfsMountTarget1D3A264C1: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikMediaEFS/EfsMountTarget1 + Properties: + FileSystemId: + Ref: AuthentikMediaEFS4AB06689 + SecurityGroups: + - Fn::GetAtt: + - AuthentikMediaEFSSecurityGroup1840BA29 + - GroupId + SubnetId: + Ref: AuthentikVpcPrivateSubnet1Subnet6748EEA3 + Type: AWS::EFS::MountTarget + AuthentikMediaEFSEfsMountTarget224E8D525: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikMediaEFS/EfsMountTarget2 + Properties: + FileSystemId: + Ref: AuthentikMediaEFS4AB06689 + SecurityGroups: + - Fn::GetAtt: + - AuthentikMediaEFSSecurityGroup1840BA29 + - GroupId + SubnetId: + Ref: AuthentikVpcPrivateSubnet2Subnet6B8E7123 + Type: AWS::EFS::MountTarget + AuthentikMediaEFSSecurityGroup1840BA29: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikMediaEFSSecurityGroup/Resource + Properties: + GroupDescription: Security group for authentik media EFS + SecurityGroupEgress: + - CidrIp: 0.0.0.0/0 + Description: Allow all outbound traffic by default + IpProtocol: '-1' + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::SecurityGroup + AuthentikMediaEFSSecurityGroupfromAuthentikStackAuthentikSG23C19B28204954496494: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikMediaEFSSecurityGroup/from AuthentikStackAuthentikSG23C19B28:2049 + Properties: + Description: from AuthentikStackAuthentikSG23C19B28:2049 + FromPort: 2049 + GroupId: + Fn::GetAtt: + - AuthentikMediaEFSSecurityGroup1840BA29 + - GroupId + IpProtocol: tcp + SourceSecurityGroupId: + Fn::GetAtt: + - AuthentikSG3040E46F + - GroupId + ToPort: 2049 + Type: AWS::EC2::SecurityGroupIngress + AuthentikRedis: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikRedis + Properties: + AutomaticFailoverEnabled: true + CacheNodeType: + Ref: RedisInstanceType + CacheSubnetGroupName: + Ref: AuthentikRedisSubnetGroup + Engine: redis + EngineVersion: + Ref: RedisVersion + NumCacheClusters: 2 + ReplicationGroupDescription: Redis cluster for authentik + SecurityGroupIds: + - Fn::GetAtt: + - RedisSGEA80AC17 + - GroupId + Type: AWS::ElastiCache::ReplicationGroup + AuthentikRedisSubnetGroup: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikRedisSubnetGroup + Properties: + Description: Subnet group for authentik ElastiCache Redis + SubnetIds: + - Ref: AuthentikVpcPrivateSubnet1Subnet6748EEA3 + - Ref: AuthentikVpcPrivateSubnet2Subnet6B8E7123 + Type: AWS::ElastiCache::SubnetGroup + AuthentikSG3040E46F: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikSG/Resource + Properties: + GroupDescription: Security Group for authentik services + SecurityGroupEgress: + - CidrIp: 0.0.0.0/0 + Description: Allow all outbound traffic by default + IpProtocol: '-1' + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::SecurityGroup + AuthentikSGfromAuthentikStackAuthentikALBSecurityGroup46E4D829900045771B43: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikSG/from AuthentikStackAuthentikALBSecurityGroup46E4D829:9000 + Properties: + Description: Load balancer to target + FromPort: 9000 + GroupId: + Fn::GetAtt: + - AuthentikSG3040E46F + - GroupId + IpProtocol: tcp + SourceSecurityGroupId: + Fn::GetAtt: + - AuthentikALBSecurityGroup2B18FEEF + - GroupId + ToPort: 9000 + Type: AWS::EC2::SecurityGroupIngress + AuthentikSecretKeyAC972960: + DeletionPolicy: Delete + Metadata: + aws:cdk:path: AuthentikStack/AuthentikSecretKey/Resource + Properties: + GenerateSecretString: + ExcludeCharacters: '"@/\' + PasswordLength: 64 + Type: AWS::SecretsManager::Secret + UpdateReplacePolicy: Delete + AuthentikServerService9C845914: + DependsOn: + - AuthentikALBAuthentikHttpsListenerAuthentikServerTargetGroup345C3479 + - AuthentikALBAuthentikHttpsListener34A9BF12 + - AuthentikServerTaskTaskRoleDefaultPolicy4C2F360F + - AuthentikServerTaskTaskRole5BB06A73 + Metadata: + aws:cdk:path: AuthentikStack/AuthentikServerService/Service + Properties: + Cluster: + Ref: AuthentikCluster54E596EF + DeploymentConfiguration: + Alarms: + AlarmNames: [] + Enable: false + Rollback: false + MaximumPercent: 200 + MinimumHealthyPercent: 50 + DesiredCount: + Ref: AuthentikServerDesiredCount + EnableECSManagedTags: false + EnableExecuteCommand: true + HealthCheckGracePeriodSeconds: 60 + LaunchType: FARGATE + LoadBalancers: + - ContainerName: AuthentikServerContainer + ContainerPort: 9000 + TargetGroupArn: + Ref: AuthentikALBAuthentikHttpsListenerAuthentikServerTargetGroup345C3479 + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: DISABLED + SecurityGroups: + - Fn::GetAtt: + - AuthentikSG3040E46F + - GroupId + Subnets: + - Ref: AuthentikVpcPrivateSubnet1Subnet6748EEA3 + - Ref: AuthentikVpcPrivateSubnet2Subnet6B8E7123 + TaskDefinition: + Ref: AuthentikServerTaskD2D47AE0 + Type: AWS::ECS::Service + AuthentikServerTaskAuthentikServerContainerLogGroup7E3C6881: + DeletionPolicy: Retain + Metadata: + aws:cdk:path: AuthentikStack/AuthentikServerTask/AuthentikServerContainer/LogGroup/Resource + Type: AWS::Logs::LogGroup + UpdateReplacePolicy: Retain + AuthentikServerTaskD2D47AE0: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikServerTask/Resource + Properties: + ContainerDefinitions: + - Command: + - server + Environment: + - Name: AUTHENTIK_POSTGRESQL__HOST + Value: + Fn::GetAtt: + - AuthentikDB6710DB92 + - Endpoint.Address + - Name: AUTHENTIK_POSTGRESQL__USER + Value: authentik + - Name: AUTHENTIK_REDIS__HOST + Value: + Fn::GetAtt: + - AuthentikRedis + - PrimaryEndPoint.Address + Essential: true + HealthCheck: + Command: + - CMD + - ak + - healthcheck + Interval: 30 + Retries: 3 + StartPeriod: 60 + Timeout: 30 + Image: + Fn::Join: + - '' + - - Ref: AuthentikImage + - ':' + - Ref: AuthentikVersion + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-group: + Ref: AuthentikServerTaskAuthentikServerContainerLogGroup7E3C6881 + awslogs-region: + Ref: AWS::Region + awslogs-stream-prefix: authentik-server + MountPoints: + - ContainerPath: /media + ReadOnly: false + SourceVolume: media + Name: AuthentikServerContainer + PortMappings: + - ContainerPort: 9000 + Protocol: tcp + RestartPolicy: + Enabled: true + Secrets: + - Name: AUTHENTIK_POSTGRESQL__PASSWORD + ValueFrom: + Fn::Join: + - '' + - - Ref: DBPassword67313E91 + - ':password::' + - Name: AUTHENTIK_SECRET_KEY + ValueFrom: + Ref: AuthentikSecretKeyAC972960 + Cpu: + Ref: AuthentikServerCPU + ExecutionRoleArn: + Fn::GetAtt: + - AuthentikServerTaskExecutionRole053E3BF5 + - Arn + Family: AuthentikStackAuthentikServerTask23085F62 + Memory: + Ref: AuthentikServerMemory + NetworkMode: awsvpc + RequiresCompatibilities: + - FARGATE + TaskRoleArn: + Fn::GetAtt: + - AuthentikServerTaskTaskRole5BB06A73 + - Arn + Volumes: + - EFSVolumeConfiguration: + AuthorizationConfig: + AccessPointId: + Ref: AuthentikMediaEFSAuthentikMediaAccessPointA60D3CC7 + IAM: ENABLED + FilesystemId: + Ref: AuthentikMediaEFS4AB06689 + TransitEncryption: ENABLED + Name: media + Type: AWS::ECS::TaskDefinition + AuthentikServerTaskExecutionRole053E3BF5: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikServerTask/ExecutionRole/Resource + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: ecs-tasks.amazonaws.com + Version: '2012-10-17' + Type: AWS::IAM::Role + AuthentikServerTaskExecutionRoleDefaultPolicy5AE74030: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikServerTask/ExecutionRole/DefaultPolicy/Resource + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + Fn::GetAtt: + - AuthentikServerTaskAuthentikServerContainerLogGroup7E3C6881 + - Arn + - Action: + - secretsmanager:GetSecretValue + - secretsmanager:DescribeSecret + Effect: Allow + Resource: + Ref: DBPassword67313E91 + - Action: + - secretsmanager:GetSecretValue + - secretsmanager:DescribeSecret + Effect: Allow + Resource: + Ref: AuthentikSecretKeyAC972960 + Version: '2012-10-17' + PolicyName: AuthentikServerTaskExecutionRoleDefaultPolicy5AE74030 + Roles: + - Ref: AuthentikServerTaskExecutionRole053E3BF5 + Type: AWS::IAM::Policy + AuthentikServerTaskTaskRole5BB06A73: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikServerTask/TaskRole/Resource + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: ecs-tasks.amazonaws.com + Version: '2012-10-17' + Type: AWS::IAM::Role + AuthentikServerTaskTaskRoleDefaultPolicy4C2F360F: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikServerTask/TaskRole/DefaultPolicy/Resource + Properties: + PolicyDocument: + Statement: + - Action: + - ssmmessages:CreateControlChannel + - ssmmessages:CreateDataChannel + - ssmmessages:OpenControlChannel + - ssmmessages:OpenDataChannel + Effect: Allow + Resource: '*' + - Action: logs:DescribeLogGroups + Effect: Allow + Resource: '*' + - Action: + - logs:CreateLogStream + - logs:DescribeLogStreams + - logs:PutLogEvents + Effect: Allow + Resource: '*' + Version: '2012-10-17' + PolicyName: AuthentikServerTaskTaskRoleDefaultPolicy4C2F360F + Roles: + - Ref: AuthentikServerTaskTaskRole5BB06A73 + Type: AWS::IAM::Policy + AuthentikVpcA1ABE6C2: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/Resource + Properties: + CidrBlock: 10.0.0.0/16 + EnableDnsHostnames: true + EnableDnsSupport: true + InstanceTenancy: default + Tags: + - Key: Name + Value: AuthentikStack/AuthentikVpc + Type: AWS::EC2::VPC + AuthentikVpcIGW53CE5190: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/IGW + Properties: + Tags: + - Key: Name + Value: AuthentikStack/AuthentikVpc + Type: AWS::EC2::InternetGateway + AuthentikVpcPrivateSubnet1DefaultRouteE7E61D7D: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PrivateSubnet1/DefaultRoute + Properties: + DestinationCidrBlock: 0.0.0.0/0 + NatGatewayId: + Ref: AuthentikVpcPublicSubnet1NATGatewayEBF2B25B + RouteTableId: + Ref: AuthentikVpcPrivateSubnet1RouteTable865DCC15 + Type: AWS::EC2::Route + AuthentikVpcPrivateSubnet1RouteTable865DCC15: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PrivateSubnet1/RouteTable + Properties: + Tags: + - Key: Name + Value: AuthentikStack/AuthentikVpc/PrivateSubnet1 + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::RouteTable + AuthentikVpcPrivateSubnet1RouteTableAssociationBBA42BB3: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PrivateSubnet1/RouteTableAssociation + Properties: + RouteTableId: + Ref: AuthentikVpcPrivateSubnet1RouteTable865DCC15 + SubnetId: + Ref: AuthentikVpcPrivateSubnet1Subnet6748EEA3 + Type: AWS::EC2::SubnetRouteTableAssociation + AuthentikVpcPrivateSubnet1Subnet6748EEA3: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PrivateSubnet1/Subnet + Properties: + AvailabilityZone: + Fn::Select: + - 0 + - Fn::GetAZs: '' + CidrBlock: 10.0.128.0/18 + MapPublicIpOnLaunch: false + Tags: + - Key: aws-cdk:subnet-name + Value: Private + - Key: aws-cdk:subnet-type + Value: Private + - Key: Name + Value: AuthentikStack/AuthentikVpc/PrivateSubnet1 + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::Subnet + AuthentikVpcPrivateSubnet2DefaultRouteB93D7A74: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PrivateSubnet2/DefaultRoute + Properties: + DestinationCidrBlock: 0.0.0.0/0 + NatGatewayId: + Ref: AuthentikVpcPublicSubnet1NATGatewayEBF2B25B + RouteTableId: + Ref: AuthentikVpcPrivateSubnet2RouteTable472C2F26 + Type: AWS::EC2::Route + AuthentikVpcPrivateSubnet2RouteTable472C2F26: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PrivateSubnet2/RouteTable + Properties: + Tags: + - Key: Name + Value: AuthentikStack/AuthentikVpc/PrivateSubnet2 + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::RouteTable + AuthentikVpcPrivateSubnet2RouteTableAssociation0276EED3: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PrivateSubnet2/RouteTableAssociation + Properties: + RouteTableId: + Ref: AuthentikVpcPrivateSubnet2RouteTable472C2F26 + SubnetId: + Ref: AuthentikVpcPrivateSubnet2Subnet6B8E7123 + Type: AWS::EC2::SubnetRouteTableAssociation + AuthentikVpcPrivateSubnet2Subnet6B8E7123: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PrivateSubnet2/Subnet + Properties: + AvailabilityZone: + Fn::Select: + - 1 + - Fn::GetAZs: '' + CidrBlock: 10.0.192.0/18 + MapPublicIpOnLaunch: false + Tags: + - Key: aws-cdk:subnet-name + Value: Private + - Key: aws-cdk:subnet-type + Value: Private + - Key: Name + Value: AuthentikStack/AuthentikVpc/PrivateSubnet2 + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::Subnet + AuthentikVpcPublicSubnet1DefaultRoute90C4189A: + DependsOn: + - AuthentikVpcVPCGW65A49376 + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PublicSubnet1/DefaultRoute + Properties: + DestinationCidrBlock: 0.0.0.0/0 + GatewayId: + Ref: AuthentikVpcIGW53CE5190 + RouteTableId: + Ref: AuthentikVpcPublicSubnet1RouteTable142C1454 + Type: AWS::EC2::Route + AuthentikVpcPublicSubnet1EIP2A4626A0: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PublicSubnet1/EIP + Properties: + Domain: vpc + Tags: + - Key: Name + Value: AuthentikStack/AuthentikVpc/PublicSubnet1 + Type: AWS::EC2::EIP + AuthentikVpcPublicSubnet1NATGatewayEBF2B25B: + DependsOn: + - AuthentikVpcPublicSubnet1DefaultRoute90C4189A + - AuthentikVpcPublicSubnet1RouteTableAssociation33E57E0C + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PublicSubnet1/NATGateway + Properties: + AllocationId: + Fn::GetAtt: + - AuthentikVpcPublicSubnet1EIP2A4626A0 + - AllocationId + SubnetId: + Ref: AuthentikVpcPublicSubnet1Subnet0C75862A + Tags: + - Key: Name + Value: AuthentikStack/AuthentikVpc/PublicSubnet1 + Type: AWS::EC2::NatGateway + AuthentikVpcPublicSubnet1RouteTable142C1454: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PublicSubnet1/RouteTable + Properties: + Tags: + - Key: Name + Value: AuthentikStack/AuthentikVpc/PublicSubnet1 + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::RouteTable + AuthentikVpcPublicSubnet1RouteTableAssociation33E57E0C: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PublicSubnet1/RouteTableAssociation + Properties: + RouteTableId: + Ref: AuthentikVpcPublicSubnet1RouteTable142C1454 + SubnetId: + Ref: AuthentikVpcPublicSubnet1Subnet0C75862A + Type: AWS::EC2::SubnetRouteTableAssociation + AuthentikVpcPublicSubnet1Subnet0C75862A: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PublicSubnet1/Subnet + Properties: + AvailabilityZone: + Fn::Select: + - 0 + - Fn::GetAZs: '' + CidrBlock: 10.0.0.0/18 + MapPublicIpOnLaunch: true + Tags: + - Key: aws-cdk:subnet-name + Value: Public + - Key: aws-cdk:subnet-type + Value: Public + - Key: Name + Value: AuthentikStack/AuthentikVpc/PublicSubnet1 + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::Subnet + AuthentikVpcPublicSubnet2DefaultRoute2E9B0EBA: + DependsOn: + - AuthentikVpcVPCGW65A49376 + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PublicSubnet2/DefaultRoute + Properties: + DestinationCidrBlock: 0.0.0.0/0 + GatewayId: + Ref: AuthentikVpcIGW53CE5190 + RouteTableId: + Ref: AuthentikVpcPublicSubnet2RouteTableF486229B + Type: AWS::EC2::Route + AuthentikVpcPublicSubnet2RouteTableAssociationDA2BDD26: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PublicSubnet2/RouteTableAssociation + Properties: + RouteTableId: + Ref: AuthentikVpcPublicSubnet2RouteTableF486229B + SubnetId: + Ref: AuthentikVpcPublicSubnet2Subnet4DFAFA5B + Type: AWS::EC2::SubnetRouteTableAssociation + AuthentikVpcPublicSubnet2RouteTableF486229B: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PublicSubnet2/RouteTable + Properties: + Tags: + - Key: Name + Value: AuthentikStack/AuthentikVpc/PublicSubnet2 + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::RouteTable + AuthentikVpcPublicSubnet2Subnet4DFAFA5B: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/PublicSubnet2/Subnet + Properties: + AvailabilityZone: + Fn::Select: + - 1 + - Fn::GetAZs: '' + CidrBlock: 10.0.64.0/18 + MapPublicIpOnLaunch: true + Tags: + - Key: aws-cdk:subnet-name + Value: Public + - Key: aws-cdk:subnet-type + Value: Public + - Key: Name + Value: AuthentikStack/AuthentikVpc/PublicSubnet2 + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::Subnet + AuthentikVpcVPCGW65A49376: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikVpc/VPCGW + Properties: + InternetGatewayId: + Ref: AuthentikVpcIGW53CE5190 + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::VPCGatewayAttachment + AuthentikWorkerService629E37E2: + DependsOn: + - AuthentikWorkerTaskTaskRoleDefaultPolicy4E74B62D + - AuthentikWorkerTaskTaskRole87C41589 + Metadata: + aws:cdk:path: AuthentikStack/AuthentikWorkerService/Service + Properties: + Cluster: + Ref: AuthentikCluster54E596EF + DeploymentConfiguration: + Alarms: + AlarmNames: [] + Enable: false + Rollback: false + MaximumPercent: 200 + MinimumHealthyPercent: 50 + DesiredCount: + Ref: AuthentikWorkerDesiredCount + EnableECSManagedTags: false + EnableExecuteCommand: true + LaunchType: FARGATE + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: DISABLED + SecurityGroups: + - Fn::GetAtt: + - AuthentikSG3040E46F + - GroupId + Subnets: + - Ref: AuthentikVpcPrivateSubnet1Subnet6748EEA3 + - Ref: AuthentikVpcPrivateSubnet2Subnet6B8E7123 + TaskDefinition: + Ref: AuthentikWorkerTaskF8F277C5 + Type: AWS::ECS::Service + AuthentikWorkerTaskAuthentikWorkerContainerLogGroupC05B4DFC: + DeletionPolicy: Retain + Metadata: + aws:cdk:path: AuthentikStack/AuthentikWorkerTask/AuthentikWorkerContainer/LogGroup/Resource + Type: AWS::Logs::LogGroup + UpdateReplacePolicy: Retain + AuthentikWorkerTaskExecutionRole2E56865A: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikWorkerTask/ExecutionRole/Resource + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: ecs-tasks.amazonaws.com + Version: '2012-10-17' + Type: AWS::IAM::Role + AuthentikWorkerTaskExecutionRoleDefaultPolicyB028D6C8: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikWorkerTask/ExecutionRole/DefaultPolicy/Resource + Properties: + PolicyDocument: + Statement: + - Action: + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + Fn::GetAtt: + - AuthentikWorkerTaskAuthentikWorkerContainerLogGroupC05B4DFC + - Arn + - Action: + - secretsmanager:GetSecretValue + - secretsmanager:DescribeSecret + Effect: Allow + Resource: + Ref: DBPassword67313E91 + - Action: + - secretsmanager:GetSecretValue + - secretsmanager:DescribeSecret + Effect: Allow + Resource: + Ref: AuthentikSecretKeyAC972960 + Version: '2012-10-17' + PolicyName: AuthentikWorkerTaskExecutionRoleDefaultPolicyB028D6C8 + Roles: + - Ref: AuthentikWorkerTaskExecutionRole2E56865A + Type: AWS::IAM::Policy + AuthentikWorkerTaskF8F277C5: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikWorkerTask/Resource + Properties: + ContainerDefinitions: + - Command: + - worker + Environment: + - Name: AUTHENTIK_POSTGRESQL__HOST + Value: + Fn::GetAtt: + - AuthentikDB6710DB92 + - Endpoint.Address + - Name: AUTHENTIK_POSTGRESQL__USER + Value: authentik + - Name: AUTHENTIK_REDIS__HOST + Value: + Fn::GetAtt: + - AuthentikRedis + - PrimaryEndPoint.Address + Essential: true + HealthCheck: + Command: + - CMD + - ak + - healthcheck + Interval: 30 + Retries: 3 + StartPeriod: 60 + Timeout: 30 + Image: + Fn::Join: + - '' + - - Ref: AuthentikImage + - ':' + - Ref: AuthentikVersion + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-group: + Ref: AuthentikWorkerTaskAuthentikWorkerContainerLogGroupC05B4DFC + awslogs-region: + Ref: AWS::Region + awslogs-stream-prefix: authentik-worker + MountPoints: + - ContainerPath: /media + ReadOnly: false + SourceVolume: media + Name: AuthentikWorkerContainer + RestartPolicy: + Enabled: true + Secrets: + - Name: AUTHENTIK_POSTGRESQL__PASSWORD + ValueFrom: + Fn::Join: + - '' + - - Ref: DBPassword67313E91 + - ':password::' + - Name: AUTHENTIK_SECRET_KEY + ValueFrom: + Ref: AuthentikSecretKeyAC972960 + Cpu: + Ref: AuthentikWorkerCPU + ExecutionRoleArn: + Fn::GetAtt: + - AuthentikWorkerTaskExecutionRole2E56865A + - Arn + Family: AuthentikStackAuthentikWorkerTask6C7D4E77 + Memory: + Ref: AuthentikWorkerMemory + NetworkMode: awsvpc + RequiresCompatibilities: + - FARGATE + TaskRoleArn: + Fn::GetAtt: + - AuthentikWorkerTaskTaskRole87C41589 + - Arn + Volumes: + - EFSVolumeConfiguration: + AuthorizationConfig: + AccessPointId: + Ref: AuthentikMediaEFSAuthentikMediaAccessPointA60D3CC7 + IAM: ENABLED + FilesystemId: + Ref: AuthentikMediaEFS4AB06689 + TransitEncryption: ENABLED + Name: media + Type: AWS::ECS::TaskDefinition + AuthentikWorkerTaskTaskRole87C41589: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikWorkerTask/TaskRole/Resource + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: ecs-tasks.amazonaws.com + Version: '2012-10-17' + Type: AWS::IAM::Role + AuthentikWorkerTaskTaskRoleDefaultPolicy4E74B62D: + Metadata: + aws:cdk:path: AuthentikStack/AuthentikWorkerTask/TaskRole/DefaultPolicy/Resource + Properties: + PolicyDocument: + Statement: + - Action: + - ssmmessages:CreateControlChannel + - ssmmessages:CreateDataChannel + - ssmmessages:OpenControlChannel + - ssmmessages:OpenDataChannel + Effect: Allow + Resource: '*' + - Action: logs:DescribeLogGroups + Effect: Allow + Resource: '*' + - Action: + - logs:CreateLogStream + - logs:DescribeLogStreams + - logs:PutLogEvents + Effect: Allow + Resource: '*' + Version: '2012-10-17' + PolicyName: AuthentikWorkerTaskTaskRoleDefaultPolicy4E74B62D + Roles: + - Ref: AuthentikWorkerTaskTaskRole87C41589 + Type: AWS::IAM::Policy + DBPassword67313E91: + DeletionPolicy: Delete + Metadata: + aws:cdk:path: AuthentikStack/DBPassword/Resource + Properties: + GenerateSecretString: + ExcludeCharacters: '"@/\' + GenerateStringKey: password + PasswordLength: 64 + SecretStringTemplate: '{"username": "authentik"}' + Type: AWS::SecretsManager::Secret + UpdateReplacePolicy: Delete + DBPasswordAttachmentAC350077: + Metadata: + aws:cdk:path: AuthentikStack/DBPassword/Attachment/Resource + Properties: + SecretId: + Ref: DBPassword67313E91 + TargetId: + Ref: AuthentikDB6710DB92 + TargetType: AWS::RDS::DBInstance + Type: AWS::SecretsManager::SecretTargetAttachment + DatabaseSG2A23C222: + Metadata: + aws:cdk:path: AuthentikStack/DatabaseSG/Resource + Properties: + GroupDescription: Security Group for authentik RDS PostgreSQL + SecurityGroupEgress: + - CidrIp: 0.0.0.0/0 + Description: Allow all outbound traffic by default + IpProtocol: '-1' + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::SecurityGroup + DatabaseSGfromAuthentikStackAuthentikSG23C19B28543226D9B076: + Metadata: + aws:cdk:path: AuthentikStack/DatabaseSG/from AuthentikStackAuthentikSG23C19B28:5432 + Properties: + Description: Allow authentik to connect to RDS PostgreSQL + FromPort: 5432 + GroupId: + Fn::GetAtt: + - DatabaseSG2A23C222 + - GroupId + IpProtocol: tcp + SourceSecurityGroupId: + Fn::GetAtt: + - AuthentikSG3040E46F + - GroupId + ToPort: 5432 + Type: AWS::EC2::SecurityGroupIngress + RedisSGEA80AC17: + Metadata: + aws:cdk:path: AuthentikStack/RedisSG/Resource + Properties: + GroupDescription: Security Group for authentik ElastiCache Redis + SecurityGroupEgress: + - CidrIp: 0.0.0.0/0 + Description: Allow all outbound traffic by default + IpProtocol: '-1' + VpcId: + Ref: AuthentikVpcA1ABE6C2 + Type: AWS::EC2::SecurityGroup + RedisSGfromAuthentikStackAuthentikSG23C19B2863790C4BCCDE: + Metadata: + aws:cdk:path: AuthentikStack/RedisSG/from AuthentikStackAuthentikSG23C19B28:6379 + Properties: + Description: Allow authentik to connect to ElastiCache Redis + FromPort: 6379 + GroupId: + Fn::GetAtt: + - RedisSGEA80AC17 + - GroupId + IpProtocol: tcp + SourceSecurityGroupId: + Fn::GetAtt: + - AuthentikSG3040E46F + - GroupId + ToPort: 6379 + Type: AWS::EC2::SecurityGroupIngress diff --git a/website/docs/install-config/upgrade.mdx b/website/docs/install-config/upgrade.mdx index 7897fdd095f0..387023e16601 100644 --- a/website/docs/install-config/upgrade.mdx +++ b/website/docs/install-config/upgrade.mdx @@ -39,7 +39,7 @@ import TabItem from "@theme/TabItem"; ``` - + In your terminal, navigate to your installation directory and run the following commands: ``` @@ -48,6 +48,14 @@ import TabItem from "@theme/TabItem"; ``` + + Navigate to your authentik AWS Cloudformation stack. Click on the **Changesets** tab and **Create changeset**. + + Select **Use existing template** and follow the prompts to upgrade. + + To upgrade to a specific version, select **Replace existing template** and use the following URL: `https://authentik-cloudformation-templates.s3.amazonaws.com/authentik.ecs.VERSION.yaml` replacing `VERSION` with the version you want to upgrade to. You can use `latest` to upgrade to the latest version. + + ## Verify your upgrade diff --git a/website/package-lock.json b/website/package-lock.json index 7dc1ec3780ba..ffaaadd83b21 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -35,6 +35,7 @@ "@docusaurus/tsconfig": "^3.6.3", "@docusaurus/types": "^3.3.2", "@types/react": "^18.3.12", + "aws-cdk": "^2.167.1", "cross-env": "^7.0.3", "prettier": "3.4.1", "typescript": "~5.7.2", @@ -6119,6 +6120,37 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/aws-cdk": { + "version": "2.167.1", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.167.1.tgz", + "integrity": "sha512-GOFe5hj7xi7i7aqkaQ2PT1jmar+Ip+qNpA7hJoH4anz98rthcl4N2X01CdHiEc61/0urobwl5358xAZIhMd21g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "cdk": "bin/cdk" + }, + "engines": { + "node": ">= 14.15.0" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/aws-cdk/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/babel-loader": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", diff --git a/website/package.json b/website/package.json index ef34c284a49e..ef99d4c34855 100644 --- a/website/package.json +++ b/website/package.json @@ -4,6 +4,7 @@ "private": true, "license": "MIT", "scripts": { + "aws-cfn": "cd docs/install-config/install/aws && cdk synth > template.yaml && ./fix_template.py", "build": "cp ../docker-compose.yml static/docker-compose.yml && cp ../schema.yml static/schema.yaml && docusaurus gen-api-docs all && cross-env NODE_OPTIONS='--max_old_space_size=65536' docusaurus build", "build-bundled": "cp ../schema.yml static/schema.yaml && docusaurus gen-api-docs all && cross-env NODE_OPTIONS='--max_old_space_size=65536' docusaurus build", "deploy": "docusaurus deploy", @@ -55,6 +56,7 @@ "@docusaurus/tsconfig": "^3.6.3", "@docusaurus/types": "^3.3.2", "@types/react": "^18.3.12", + "aws-cdk": "^2.167.1", "cross-env": "^7.0.3", "prettier": "3.4.1", "typescript": "~5.7.2", diff --git a/website/sidebars.js b/website/sidebars.js index 2ecb16af099a..87995f0ef67b 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -97,6 +97,7 @@ export default { items: [ "install-config/install/docker-compose", "install-config/install/kubernetes", + "install-config/install/aws/index", ], }, {