diff --git a/README.rst b/README.rst index 4ff9a31..0b3efe7 100644 --- a/README.rst +++ b/README.rst @@ -27,9 +27,9 @@ Deploy to AWS Verify and adapt all the settings and configuration you find in **aws.yml** file to match your environment. Once that is done, all you have to do is deploy to AWS via -.. code-block:: yaml +.. code-block:: - ecs-compose-x up -f docker-compose.yml -f aws.yml -n wordpress-demo + ecs-compose-x up -f docker-compose.yml -f aws.yml -p wordpress-demo .. hint:: @@ -37,3 +37,43 @@ Once that is done, all you have to do is deploy to AWS via ecs-compose-x init +Adding WAF +---------- + +To add WAF, simply the run the command including the ``wafv2.yaml`` to the command line + +.. code-block:: + + ecs-compose-x up -f docker-compose.yml -f aws.yml -p wordpress-demo -f wafv2.yml + + +.. note:: + + Enabling the WAF with the defined rules here will deny access to ``/wp-admin``. You can create rules to allow your IP addresses to access it. + + +x-elbv2 Conditions +------------------- + +You will notice in the conditions for ``x-elbv2`` pointing to the service, a ``Conditions`` section. +There, we indicate that we want traffic to be sent to wordbress **only if the hostname matches**. +By default, the ELBv2 will be configured to return 418 + +.. code-block:: + + curl -k https://wordpr-wordp-sw06gyb58v6i-1922613310.eu-west-1.elb.amazonaws.com/ -v + < HTTP/2 418 + < server: awselb/2.0 + < date: Wed, 28 Feb 2024 10:35:11 GMT + < content-type: application/json; charset=utf-8 + < content-length: 24 + < + * Connection #0 to host wordpr-wordp-sw06gyb58v6i-1922613310.eu-west-1.elb.amazonaws.com left intact + {"Info": "Be our guest"} + +I have found this is a great way to rebuke crawlers that try their luck on an IP addresses basis instead of hostnames. +If I try to get on the hostname itself, i.e ``wordpress.demos.bdd-testing.compose-x.io``, I can reach it and all subsequent +pages. + +To further secure the wp-admin path, I recommend to use the x-cognito integration to force going through authentication +before you can even hit the WP Admin login page. diff --git a/aws.yml b/aws.yml index 5340802..9cacd7c 100644 --- a/aws.yml +++ b/aws.yml @@ -1,145 +1,129 @@ -version: '3.8' - services: wordpress: deploy: resources: reservations: - cpus: 1.0 + cpus: "1.0" memory: 1G + environment: + WORDPRESS_SKIP_INSTALL: 'no' + WORDPRESS_USERNAME: superuser + WORDPRESS_PASSWORD: 'ch@ngeM3Please' volumes: - persistent:/bitnami/wordpress - environment: - WORDPRESS_SKIP_INSTALL: "no" - x-scaling: - Range: 1-5 x-alarms: Predefined: HighRamUsageAndMaxScaledOut: Topics: - x-sns: alarms - - + x-scaling: + Range: 1-5 +version: '3.8' volumes: persistent: x-efs: + MacroParameters: + EnforceIamAuth: true Properties: - LifecyclePolicies: + LifecyclePolicies: null TransitionToIA: AFTER_14_DAYS - MacroParameters: - EnforceIamAuth: True - -x-sns: - Topics: - alarms: {} - -# Storage settings +x-acm: + wordpress-demo: + Lookup: + Tags: + - Name: wildcard.${DOMAIN_NAME:-demos.bdd-testing.compose-x.io} +x-cluster: + Properties: + CapacityProviders: + - FARGATE + - FARGATE_SPOT + ClusterName: demo + DefaultCapacityProviderStrategy: + - Base: 2 + CapacityProvider: FARGATE_SPOT + Weight: 2 + - CapacityProvider: FARGATE + Weight: 1 +x-elbv2: + wordpress-lb: + DnsAliases: + - Route53Zone: x-route53::PublicZone + Names: + - wordpress.${DOMAIN_NAME:-demos.bdd-testing.compose-x.io} + Listeners: + - DefaultActions: + - Redirect: HTTP_TO_HTTPS + Port: 80 + Protocol: HTTP + - Certificates: + - x-acm: wordpress-demo + Port: 443 + Protocol: HTTPS + Targets: + - Conditions: + - Field: host-header + HostHeaderConfig: + Values: + - wordpress.${DOMAIN_NAME:-demos.bdd-testing.compose-x.io} + name: wordpress:wordpress + MacroParameters: + Ingress: + ExtSources: + - Description: ANY + IPv4: 0.0.0.0/0 + Name: ANY + Properties: + Scheme: internet-facing + Type: application + Services: + wordpress:wordpress: + healthcheck: 8080:HTTP:/:7:2:15:5 + port: 8080 + protocol: HTTP x-rds: wordpress-db: Properties: - Engine: "aurora-mysql" - EngineVersion: "5.7" BackupRetentionPeriod: 1 DatabaseName: wordpress - StorageEncrypted: True + Engine: aurora-mysql + EngineVersion: '5.7' + StorageEncrypted: true Tags: - Key: Name - Value: "dummy-db" + Value: dummy-db Services: - - name: wordpress - access: RW + wordpress: + Access: + DBCluster: RO SecretsMappings: Mappings: - host: MARIADB_HOST - port: MARIADB_PORT_NUMBER - username: WORDPRESS_DATABASE_USER - password: WORDPRESS_DATABASE_PASSWORD dbname: WORDPRESS_DATABASE_NAME - + host: WORDPRESS_DATABASE_HOST + password: WORDPRESS_DATABASE_PASSWORD + port: WORDPRESS_DATABASE_PORT_NUMBER + username: WORDPRESS_DATABASE_USER +x-route53: + PublicZone: + Lookup: true + Name: bdd-testing.compose-x.io x-s3: wp-data-bucket: Properties: AccessControl: BucketOwnerFullControl - PublicAccessBlockConfiguration: - BlockPublicAcls: True - BlockPublicPolicy: True - IgnorePublicAcls: True - RestrictPublicBuckets: False BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 + PublicAccessBlockConfiguration: + BlockPublicAcls: true + BlockPublicPolicy: true + IgnorePublicAcls: true + RestrictPublicBuckets: false Services: - - name: wordpress - access: - Bucket: ListOnly - Objects: RW - - -# DNS and Ingress settings - -x-dns: - PublicZone: - Name: demos.lambda-my-aws.io - Lookup: True - Records: - - Properties: - Name: wordpress.demos.lambda-my-aws.io - Type: A - Target: x-elbv2::wordpress-lb - - -x-acm: - wordpress-demo: - Lookup: - Tags: - - Name: demos.lambda-my-aws.io - - wildcard: "True" - -x-elbv2: - wordpress-lb: - Properties: - Scheme: internet-facing - Type: application - MacroParameters: - Ingress: - ExtSources: - - IPv4: 0.0.0.0/0 - Name: ANY - Description: "ANY" - Listeners: - - Port: 80 - Protocol: HTTP - DefaultActions: - - Redirect: HTTP_TO_HTTPS - - Port: 443 - Protocol: HTTPS - Certificates: - - x-acm: wordpress-demo - Targets: - - name: wordpress:wordpress - access: / - - Services: - - name: wordpress:wordpress - port: 8080 - protocol: HTTP - healthcheck: 8080:HTTP:/:7:2:15:5 - - -# ECS Cluster settings - - -x-cluster: - Properties: - CapacityProviders: - - FARGATE - - FARGATE_SPOT - ClusterName: demo - DefaultCapacityProviderStrategy: - - Base: 2 - CapacityProvider: FARGATE_SPOT - Weight: 2 - - CapacityProvider: FARGATE - Weight: 1 + wordpress: + Access: + bucket: ListOnly + objects: RW +x-sns: + alarms: {} diff --git a/local.yml b/docker-compose.override.yaml similarity index 100% rename from local.yml rename to docker-compose.override.yaml diff --git a/docker-compose.yml b/docker-compose.yml index b14b030..493146a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,10 +6,12 @@ version: '3.8' services: wordpress: image: public.ecr.aws/bitnami/wordpress:latest + x-docker_opts: + InterpolateWithDigest: true ports: - '80:8080' - '443:8443' - user: 1001 + user: '1001' volumes: persistent: diff --git a/requirements.txt b/requirements.txt index fe5f37c..efa03b1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -ecs_composex=>0.13.0 +ecs_composex>=1.0 + diff --git a/wafv2.yml b/wafv2.yml new file mode 100644 index 0000000..ba8d1c6 --- /dev/null +++ b/wafv2.yml @@ -0,0 +1,113 @@ + +version: "3.8" +x-wafv2_webacl: + NewWp-WebAcl: + LoadBalancers: + - wordpress-lb + Properties: + Description: wafv2-webacl-dev + DefaultAction: + Allow: {} + Scope: REGIONAL + Rules: + - Priority: 0 + Statement: + ManagedRuleGroupStatement: + VendorName: AWS + RuleActionOverrides: [] + ManagedRuleGroupConfigs: [] + ExcludedRules: [] + Name: AWSManagedRulesAmazonIpReputationList + OverrideAction: + None: {} + RuleLabels: [] + VisibilityConfig: + MetricName: AWS-AWSManagedRulesAmazonIpReputationList + SampledRequestsEnabled: true + CloudWatchMetricsEnabled: true + Name: AWS-AWSManagedRulesAmazonIpReputationList + - Priority: 1 + Statement: + ManagedRuleGroupStatement: + VendorName: AWS + RuleActionOverrides: [] + ManagedRuleGroupConfigs: [] + ExcludedRules: [] + Name: AWSManagedRulesAnonymousIpList + OverrideAction: + None: {} + RuleLabels: [] + VisibilityConfig: + MetricName: AWS-AWSManagedRulesAnonymousIpList + SampledRequestsEnabled: true + CloudWatchMetricsEnabled: true + Name: AWS-AWSManagedRulesAnonymousIpList + - Priority: 2 + Statement: + ManagedRuleGroupStatement: + VendorName: AWS + RuleActionOverrides: [] + ManagedRuleGroupConfigs: [] + ExcludedRules: [] + Name: AWSManagedRulesUnixRuleSet + OverrideAction: + None: {} + RuleLabels: [] + VisibilityConfig: + MetricName: AWS-AWSManagedRulesUnixRuleSet + SampledRequestsEnabled: true + CloudWatchMetricsEnabled: true + Name: AWS-AWSManagedRulesUnixRuleSet + - Priority: 3 + Statement: + ManagedRuleGroupStatement: + VendorName: AWS + RuleActionOverrides: [] + ManagedRuleGroupConfigs: [] + ExcludedRules: [] + Name: AWSManagedRulesAdminProtectionRuleSet + OverrideAction: + None: {} + RuleLabels: [] + VisibilityConfig: + MetricName: AWS-AWSManagedRulesAdminProtectionRuleSet + SampledRequestsEnabled: true + CloudWatchMetricsEnabled: true + Name: AWS-AWSManagedRulesAdminProtectionRuleSet + - Priority: 4 + Statement: + ManagedRuleGroupStatement: + VendorName: AWS + RuleActionOverrides: [] + ManagedRuleGroupConfigs: [] + ExcludedRules: [] + Name: AWSManagedRulesKnownBadInputsRuleSet + OverrideAction: + None: {} + RuleLabels: [] + VisibilityConfig: + MetricName: AWS-AWSManagedRulesKnownBadInputsRuleSet + SampledRequestsEnabled: true + CloudWatchMetricsEnabled: true + Name: AWS-AWSManagedRulesKnownBadInputsRuleSet + - Priority: 5 + Statement: + ManagedRuleGroupStatement: + VendorName: AWS + RuleActionOverrides: [] + ManagedRuleGroupConfigs: [] + ExcludedRules: [] + Name: AWSManagedRulesCommonRuleSet + OverrideAction: + None: {} + RuleLabels: [] + VisibilityConfig: + MetricName: AWS-AWSManagedRulesCommonRuleSet + SampledRequestsEnabled: true + CloudWatchMetricsEnabled: true + Name: AWS-AWSManagedRulesCommonRuleSet + VisibilityConfig: + MetricName: wafv2-webacl-dev + SampledRequestsEnabled: true + CloudWatchMetricsEnabled: true + Name: wafv2-webacl-dev