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