6662fbeb8c48ba4a01c1caaa7eed5cf8070dfa9d
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/LandscapeConstants.java
| ... | ... | @@ -72,6 +72,18 @@ public interface LandscapeConstants { |
| 72 | 72 | * "default" version. See, e.g., {@link LaunchTemplateSpecification#version()}. |
| 73 | 73 | */ |
| 74 | 74 | String DEFAULT_LAUNCH_TEMPLATE_VERSION_NAME = "$Default"; |
| 75 | + |
|
| 76 | + /** |
|
| 77 | + * When we use AWS Web Application Firewall (WAF) to protect a web application, we tag the web ACLs using this as a |
|
| 78 | + * tag key. The tag value then identifies the purpose, e.g., using the value of {@link #WEB_ACL_GEOBLOCKING_PURPOSE}. |
|
| 79 | + */ |
|
| 80 | + String WEB_ACL_PURPOSE_TAG = "web-acl-purpose"; |
|
| 81 | + |
|
| 82 | + /** |
|
| 83 | + * A possible tag value for the {@link #WEB_ACL_PURPOSE_TAG} tag key, on a WAF (Web Application Firewall) web ACL |
|
| 84 | + * indicating that the web ACL is used for geoblocking. |
|
| 85 | + */ |
|
| 86 | + String WEB_ACL_GEOBLOCKING_PURPOSE = "geoblocking"; |
|
| 75 | 87 | |
| 76 | 88 | InstanceType[] INSTANCE_TYPES_BANNED_FROM_INSTANCE_BASED_NLB_TARGET_GROUPS = new InstanceType[] { InstanceType.CC1_4_XLARGE, InstanceType.C1_MEDIUM, InstanceType.C1_XLARGE, |
| 77 | 89 | InstanceType.CC2_8_XLARGE, InstanceType.CG1_4_XLARGE, InstanceType.CR1_8_XLARGE, InstanceType.G2_2_XLARGE, |
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsLandscapeImpl.java
| ... | ... | @@ -197,6 +197,9 @@ import software.amazon.awssdk.services.route53.model.TestDnsAnswerResponse; |
| 197 | 197 | import software.amazon.awssdk.services.route53.paginators.ListResourceRecordSetsIterable; |
| 198 | 198 | import software.amazon.awssdk.services.sts.StsClient; |
| 199 | 199 | import software.amazon.awssdk.services.sts.model.Credentials; |
| 200 | +import software.amazon.awssdk.services.wafv2.Wafv2Client; |
|
| 201 | +import software.amazon.awssdk.services.wafv2.model.ListWebAcLsResponse; |
|
| 202 | +import software.amazon.awssdk.services.wafv2.model.Scope; |
|
| 200 | 203 | |
| 201 | 204 | public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey> { |
| 202 | 205 | private static final String SSL_SECURITY_POLICY = "ELBSecurityPolicy-FS-1-2-Res-2019-08"; |
| ... | ... | @@ -305,6 +308,10 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey> |
| 305 | 308 | return getClient(ElasticLoadBalancingV2Client.builder(), region); |
| 306 | 309 | } |
| 307 | 310 | |
| 311 | + private Wafv2Client getWafClient(Region region) { |
|
| 312 | + return getClient(Wafv2Client.builder(), region); |
|
| 313 | + } |
|
| 314 | + |
|
| 308 | 315 | private ElasticLoadBalancingV2AsyncClient getLoadBalancingAsyncClient(Region region) { |
| 309 | 316 | return getClient(ElasticLoadBalancingV2AsyncClient.builder(), region); |
| 310 | 317 | } |
| ... | ... | @@ -352,9 +359,25 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey> |
| 352 | 359 | final ApplicationLoadBalancer<ShardingKey> result = new ApplicationLoadBalancerImpl<>(region, response.loadBalancers().iterator().next(), this); |
| 353 | 360 | createLoadBalancerHttpListener(result); |
| 354 | 361 | createLoadBalancerHttpsListener(result); |
| 362 | + getWafACLsByTagAndAssociateWithALB(LandscapeConstants.WEB_ACL_PURPOSE_TAG, LandscapeConstants.WEB_ACL_GEOBLOCKING_PURPOSE, result.getArn(), awsRegion); |
|
| 355 | 363 | return result; |
| 356 | 364 | } |
| 357 | 365 | |
| 366 | + private void getWafACLsByTagAndAssociateWithALB(String tagKey, String tagValue, String albArn, Region region) { |
|
| 367 | + final Wafv2Client wafClient = getWafClient(region); |
|
| 368 | + // Step 1: list all REGIONAL Web ACLs |
|
| 369 | + final ListWebAcLsResponse listResp = wafClient.listWebACLs(b->b.scope(Scope.REGIONAL)); |
|
| 370 | + listResp.webACLs().stream().filter(aclSummary -> |
|
| 371 | + // Step 2: filter the ACLs down to those with the right tag |
|
| 372 | + wafClient.listTagsForResource(b->b.resourceARN(aclSummary.arn())).tagInfoForResource().tagList().stream() |
|
| 373 | + .anyMatch(tag -> tag.key().equals(tagKey) && tag.value().equals(tagValue))) |
|
| 374 | + .forEach(aclSummary -> |
|
| 375 | + // Step 3: associate the ALB with those Web ACLs |
|
| 376 | + wafClient.associateWebACL(b->b |
|
| 377 | + .webACLArn(aclSummary.arn()) |
|
| 378 | + .resourceArn(albArn))); |
|
| 379 | + } |
|
| 380 | + |
|
| 358 | 381 | private Subnet getSubnetForAvailabilityZoneInSameVpcAsSecurityGroup(AwsAvailabilityZone az, SecurityGroup securityGroup, Region region) { |
| 359 | 382 | final Ec2Client ec2Client = getEc2Client(region); |
| 360 | 383 | final String vpcId = ec2Client.describeSecurityGroups(b->b.groupIds(securityGroup.getId())).securityGroups().iterator().next().vpcId(); |
wiki/info/landscape/amazon-ec2.md
| ... | ... | @@ -139,7 +139,21 @@ In addition to a default re-direct for the "/" path, the following four ALB list |
| 139 | 139 | - if the request method is ``GET`` then forward to the public target group |
| 140 | 140 | - forward all other request for the hostname to the master target group |
| 141 | 141 | |
| 142 | -### MongoDB Replica Sets |
|
| 142 | +### Web Application Firewall (WAF) and Web ACLs for Geoblocking |
|
| 143 | + |
|
| 144 | +In order to be able to block requests from certain regions or countries based on sanctions or other bans, as well as to see improved statistics about web requests hitting the site (such as the country from where requests originate, or a classification of bot vs. non-bot requests) across all our application load balancers (ALBs), we can use the AWS Web Application Firewall (WAF) and its Web Access Control Lists (Web ACLs). These Web ACLs are defined per AWS Region, so in case of a cross-region scenarios like the Olympic Summer Games, Web ACLs have to be defined in each region supported. |
|
| 145 | + |
|
| 146 | +As of today, we are required to block access from Russia, Belarus, North Korea, and Iran. |
|
| 147 | + |
|
| 148 | +Any geo-blocking Web ACL that shall automatically be associated with ALBs that are created through our landscape automation have to be tagged with tag key ``web-acl-purpose`` (see ``LandscapeConstants.WEB_ACL_PURPOSE_TAG``) with value ``geoblocking`` (see ``LandscapeConstants.WEB_ACL_GEOBLOCKING_PURPOSE``). Tagging a Web ACL, as of this writing, is not possible through the AWS Web Console but only through the command line interface (CLI) or API. A command-line way to tag a Web ACL accordingly would look like this (adjust your Web ACL's ARN...): |
|
| 149 | +``` |
|
| 150 | + aws wafv2 tag-resource \ |
|
| 151 | + --resource-arn arn:aws:wafv2:eu-west-1:017363970217:regional/webacl/GeoBlocking/1f1c421e-994c-4c67-ba15-75375448c5c5 \ |
|
| 152 | + --tags Key=web-acl-purpose,Value=geoblocking |
|
| 153 | +``` |
|
| 154 | +Note that in order to run this command you have to have valid credentials for the AWS region you're targeting with the request. Also consider using the ``--region`` argument if you're trying to tag a Web ACL in a region other than your AWS CLI's default region. Check your ``~/.aws/config`` file. Also see ``configuration/environments_scripts/repo/usr/local/bin/awsmfalogon.sh`` for logging on to the AWS CLI. |
|
| 155 | + |
|
| 156 | +### MongoDB Replica Setsn |
|
| 143 | 157 | |
| 144 | 158 | There are currently three MongoDB replica sets: |
| 145 | 159 | |
| ... | ... | @@ -607,7 +621,7 @@ The `crontab-update-authorized-keys@HOME_DIR` snippet has a randomized sleeping |
| 607 | 621 | |
| 608 | 622 | ## Legacy Documentation for Manual Operations |
| 609 | 623 | |
| 610 | -Most of the things that follow should be obsolete by now because the [automated procedures](#amazon-ec2-for-sap-sailing-analytics_automated-procedures) should avoid the need for manual steps. Yet, should automatic procedures fail or should a deeper understanding of the things that have been automated become necessary, the following documentation may still be of value. |
|
| 624 | +Most of the things that follow should be obsolete by now because the [automated procedures](#automated-procedures) should avoid the need for manual steps. Yet, should automatic procedures fail or should a deeper understanding of the things that have been automated become necessary, the following documentation may still be of value. |
|
| 611 | 625 | |
| 612 | 626 | #### Starting an instance |
| 613 | 627 |