Skip to content

Commit

Permalink
[RW-11295][risk=low] Create DNS record to route GAR traffic to restri…
Browse files Browse the repository at this point in the history
…cted.googleapi.com (#290)

* gar support

* gar support

* typo

* typo
  • Loading branch information
yonghaoy authored Jan 8, 2024
1 parent 0b206f9 commit a59f323
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package bio.terra.buffer.service.resource.flight;

import static bio.terra.buffer.service.resource.FlightMapKeys.GOOGLE_PROJECT_ID;
import static bio.terra.buffer.service.resource.flight.GoogleProjectConfigUtils.*;
import static bio.terra.buffer.service.resource.flight.GoogleProjectConfigUtils.enableGcrPrivateGoogleAccess;
import static bio.terra.buffer.service.resource.flight.GoogleProjectConfigUtils.usePrivateGoogleAccess;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.GAR_MANAGED_ZONE_NAME;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.GCR_MANAGED_ZONE_NAME;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.MANAGED_ZONE_NAME;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.NETWORK_NAME;
Expand Down Expand Up @@ -54,6 +56,14 @@ public class CreateDnsZoneStep implements Step {
.setDnsName("gcr.io.")
.setVisibility("private");

@VisibleForTesting
public static final ManagedZone GAR_MANAGED_ZONE_TEMPLATE =
new ManagedZone()
.setName(GAR_MANAGED_ZONE_NAME)
.setDescription("Routes pkg.dev to restricted.googleapis.com")
.setDnsName("pkg.dev.")
.setVisibility("private");

private final Logger logger = LoggerFactory.getLogger(CreateDnsZoneStep.class);
private final CloudComputeCow computeCow;
private final DnsCow dnsCow;
Expand Down Expand Up @@ -85,6 +95,10 @@ public StepResult doStep(FlightContext flightContext) throws RetryException {
createManagedDnsZone(projectId, network, GCR_MANAGED_ZONE_TEMPLATE);
}

if (enableGarPrivateGoogleAccess(gcpProjectConfig)) {
createManagedDnsZone(projectId, network, GAR_MANAGED_ZONE_TEMPLATE);
}

} catch (IOException e) {
logger.info("Error when configuring DNS ", e);
return new StepResult(StepStatus.STEP_RESULT_FAILURE_RETRY, e);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package bio.terra.buffer.service.resource.flight;

import static bio.terra.buffer.service.resource.FlightMapKeys.GOOGLE_PROJECT_ID;
import static bio.terra.buffer.service.resource.flight.GoogleProjectConfigUtils.*;
import static bio.terra.buffer.service.resource.flight.GoogleProjectConfigUtils.enableGcrPrivateGoogleAccess;
import static bio.terra.buffer.service.resource.flight.GoogleProjectConfigUtils.usePrivateGoogleAccess;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.GAR_MANAGED_ZONE_NAME;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.GCR_MANAGED_ZONE_NAME;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.MANAGED_ZONE_NAME;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.getResource;
Expand All @@ -27,13 +29,15 @@

/** Configs record set for DNS. See {@link CreateDnsZoneStep} */
public class CreateResourceRecordSetStep implements Step {
private static final List<String> RESTRICT_GOOGLE_API_A_RECORD_IP_ADDRESS =
ImmutableList.of("199.36.153.4", "199.36.153.5", "199.36.153.6", "199.36.153.7");

@VisibleForTesting
public static final ResourceRecordSet RESTRICT_API_A_RECORD =
new ResourceRecordSet()
.setType("A")
.setName("restricted.googleapis.com.")
.setRrdatas(
ImmutableList.of("199.36.153.4", "199.36.153.5", "199.36.153.6", "199.36.153.7"))
.setRrdatas(RESTRICT_GOOGLE_API_A_RECORD_IP_ADDRESS)
.setTtl(300);

@VisibleForTesting
Expand All @@ -49,8 +53,7 @@ public class CreateResourceRecordSetStep implements Step {
new ResourceRecordSet()
.setType("A")
.setName("gcr.io.")
.setRrdatas(
ImmutableList.of("199.36.153.4", "199.36.153.5", "199.36.153.6", "199.36.153.7"))
.setRrdatas(RESTRICT_GOOGLE_API_A_RECORD_IP_ADDRESS)
.setTtl(300);

@VisibleForTesting
Expand All @@ -61,6 +64,22 @@ public class CreateResourceRecordSetStep implements Step {
.setRrdatas(ImmutableList.of("gcr.io."))
.setTtl(300);

@VisibleForTesting
public static final ResourceRecordSet GAR_A_RECORD =
new ResourceRecordSet()
.setType("A")
.setName("pkg.dev.")
.setRrdatas(RESTRICT_GOOGLE_API_A_RECORD_IP_ADDRESS)
.setTtl(300);

@VisibleForTesting
public static final ResourceRecordSet GAR_CNAME_RECORD =
new ResourceRecordSet()
.setType("CNAME")
.setName("*.pkg.dev.")
.setRrdatas(ImmutableList.of("pkg.dev."))
.setTtl(300);

private final Logger logger = LoggerFactory.getLogger(CreateResourceRecordSetStep.class);
private final DnsCow dnsCow;
private final GcpProjectConfig gcpProjectConfig;
Expand All @@ -87,6 +106,10 @@ public StepResult doStep(FlightContext flightContext) throws RetryException {
createRecordSetForDnsZone(
projectId, GCR_MANAGED_ZONE_NAME, ImmutableList.of(GCR_A_RECORD, GCR_CNAME_RECORD));
}
if (enableGarPrivateGoogleAccess(gcpProjectConfig)) {
createRecordSetForDnsZone(
projectId, GAR_MANAGED_ZONE_NAME, ImmutableList.of(GAR_A_RECORD, GAR_CNAME_RECORD));
}
} catch (IOException e) {
logger.info("Error when configuring ResourceRecordSets ", e);
return new StepResult(StepStatus.STEP_RESULT_FAILURE_RETRY, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ public static boolean enableGcrPrivateGoogleAccess(GcpProjectConfig gcpProjectCo
&& gcpProjectConfig.getNetwork().isEnableCloudRegistryPrivateGoogleAccess();
}

/** Checks if private Google Access enabled for gcr.io. */
public static boolean enableGarPrivateGoogleAccess(GcpProjectConfig gcpProjectConfig) {
return gcpProjectConfig.getNetwork() != null
&& gcpProjectConfig.getNetwork().isEnableArtifactRegistryPrivateGoogleAccess() != null
&& gcpProjectConfig.getNetwork().isEnableArtifactRegistryPrivateGoogleAccess();
}

/** Whether to allow CGP VMs have internet access. */
public static boolean blockBatchInternetAccess(GcpProjectConfig gcpProjectConfig) {
return gcpProjectConfig.getNetwork() != null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ public class GoogleUtils {
@VisibleForTesting
public static final String MANAGED_ZONE_NAME = "private-google-access-dns-zone";

/** The private DNS zone name. */
/** The private DNS zone name for GCR. */
@VisibleForTesting
public static final String GCR_MANAGED_ZONE_NAME = "private-google-access-gcr-dns-zone";
/** The private DNS zone name for GAR. */
public static final String GAR_MANAGED_ZONE_NAME = "private-google-access-gar-dns-zone";

/** All project will use the same sub network name. */
@VisibleForTesting public static final String SUBNETWORK_NAME = "subnetwork";
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/config/dev/pool_schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ poolConfigs:
- poolId: "vpc_sc_v11"
size: 300
resourceConfigName: "vpc_sc_v11"
- poolId: "vpc_sc_v12"
size: 300
resourceConfigName: "vpc_sc_v12"
- poolId: "workspace_manager_v11"
size: 500
resourceConfigName: "workspace_manager_v11"
41 changes: 41 additions & 0 deletions src/main/resources/config/dev/resource-config/vpc_sc_v12.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# # Projects with VPC-SC configuration
---
configName: "vpc_sc_v12"
gcpProjectConfig:
projectIdSchema:
prefix: "terra-vpc-sc-dev"
scheme: "RANDOM_CHAR"
# test.firecloud.org/dev/for_vpc_sc_unclaimed
parentFolderId: "1061905712535"
billingAccount: "01A82E-CA8A14-367457"
enabledApis:
- "bigquery-json.googleapis.com"
- "compute.googleapis.com"
- "container.googleapis.com"
- "cloudbilling.googleapis.com"
- "clouderrorreporting.googleapis.com"
- "cloudkms.googleapis.com"
- "cloudtrace.googleapis.com"
- "containerregistry.googleapis.com"
- "dataflow.googleapis.com"
- "dataproc.googleapis.com"
- "dns.googleapis.com"
- "lifesciences.googleapis.com"
- "logging.googleapis.com"
- "monitoring.googleapis.com"
- "serviceusage.googleapis.com"
- "storage-api.googleapis.com"
- "storage-component.googleapis.com"
network:
enableNetworkMonitoring: "true"
enablePrivateGoogleAccess: "true"
enableCloudRegistryPrivateGoogleAccess: "true"
enableArtifactRegistryPrivateGoogleAccess: "true"
blockBatchInternetAccess: "true"
kubernetesEngine:
createGkeDefaultServiceAccount: "true"
serviceUsage:
bigQuery:
overrideBigQueryDailyUsageQuota: true
bigQueryDailyUsageQuotaOverrideValueMebibytes: 38146972 # 40 TB
securityGroup: "high"
5 changes: 5 additions & 0 deletions src/main/resources/config/resource_schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ components:
Whether to config Private Google Access for gcr.io.
type: boolean
default: false
enableArtifactRegistryPrivateGoogleAccess:
description: |-
Whether to config Private Google Access for Google Artifact Registry.
type: boolean
default: false
blockBatchInternetAccess:
description: |-
Whether to allow GCE VMs have internet access for batch analysis. If ture, few firewall rules will be created to block egress
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static bio.terra.buffer.integration.IntegrationUtils.pollUntilResourcesMatch;
import static bio.terra.buffer.integration.IntegrationUtils.preparePool;
import static bio.terra.buffer.service.resource.FlightMapKeys.RESOURCE_CONFIG;
import static bio.terra.buffer.service.resource.flight.CreateDnsZoneStep.GAR_MANAGED_ZONE_TEMPLATE;
import static bio.terra.buffer.service.resource.flight.CreateDnsZoneStep.GCR_MANAGED_ZONE_TEMPLATE;
import static bio.terra.buffer.service.resource.flight.CreateDnsZoneStep.MANAGED_ZONE_TEMPLATE;
import static bio.terra.buffer.service.resource.flight.CreateFirewallRuleStep.ALLOW_EGRESS_INTERNAL;
Expand Down Expand Up @@ -41,10 +42,7 @@
import static bio.terra.buffer.service.resource.flight.CreateProjectStep.SECURITY_GROUP_LABEL_KEY;
import static bio.terra.buffer.service.resource.flight.CreateProjectStep.SUB_NETWORK_LABEL_KEY;
import static bio.terra.buffer.service.resource.flight.CreateProjectStep.createValidLabelValue;
import static bio.terra.buffer.service.resource.flight.CreateResourceRecordSetStep.GCR_A_RECORD;
import static bio.terra.buffer.service.resource.flight.CreateResourceRecordSetStep.GCR_CNAME_RECORD;
import static bio.terra.buffer.service.resource.flight.CreateResourceRecordSetStep.RESTRICT_API_A_RECORD;
import static bio.terra.buffer.service.resource.flight.CreateResourceRecordSetStep.RESTRICT_API_CNAME_RECORD;
import static bio.terra.buffer.service.resource.flight.CreateResourceRecordSetStep.*;
import static bio.terra.buffer.service.resource.flight.CreateRouteStep.DEFAULT_GATEWAY;
import static bio.terra.buffer.service.resource.flight.CreateRouteStep.ROUTE_NAME;
import static bio.terra.buffer.service.resource.flight.CreateRouterNatStep.NAT_IP_ALLOCATION;
Expand All @@ -54,16 +52,7 @@
import static bio.terra.buffer.service.resource.flight.DeleteDefaultFirewallRulesStep.DEFAULT_FIREWALL_NAMES;
import static bio.terra.buffer.service.resource.flight.GoogleProjectConfigUtils.REGION_TO_IP_RANGE;
import static bio.terra.buffer.service.resource.flight.GoogleProjectConfigUtils.getRegionToIpRange;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.DEFAULT_NETWORK_NAME;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.GCR_MANAGED_ZONE_NAME;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.MANAGED_ZONE_NAME;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.NAT_NAME_PREFIX;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.NAT_ROUTER_NAME_PREFIX;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.NETWORK_NAME;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.RESTRICTED_GOOGLE_IP_ADDRESS;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.SUBNETWORK_NAME;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.projectIdToName;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.resourceExists;
import static bio.terra.buffer.service.resource.flight.GoogleUtils.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
Expand Down Expand Up @@ -254,7 +243,8 @@ public void testCreateGoogleProject_enablePrivateGoogleAccessAndMonitoringAndSsh
}

@Test
public void testCreateGoogleProject_blockInternetAccessWithGcrDnsEnabled() throws Exception {
public void testCreateGoogleProject_blockInternetAccessWithGcrAndGarDnsEnabled()
throws Exception {
FlightManager manager =
new FlightManager(
bufferDao, flightSubmissionFactoryImpl, stairwayComponent, transactionTemplate);
Expand All @@ -267,6 +257,7 @@ public void testCreateGoogleProject_blockInternetAccessWithGcrDnsEnabled() throw
.enableNetworkMonitoring(true)
.enablePrivateGoogleAccess(true)
.enableCloudRegistryPrivateGoogleAccess(true)
.enableArtifactRegistryPrivateGoogleAccess(true)
.blockBatchInternetAccess(true)));

String flightId = manager.submitCreationFlight(pool).get();
Expand All @@ -278,6 +269,7 @@ public void testCreateGoogleProject_blockInternetAccessWithGcrDnsEnabled() throw
assertRouteExists(project);
assertDnsExists(project);
assertGcrDnsExists(project);
assertGarDnsExists(project);
assertDefaultVpcNotExists(project);
assertFirewallRulesExistForBlockInternetAccess(project);
assertRouterNatNotExists(project);
Expand Down Expand Up @@ -947,6 +939,29 @@ private void assertGcrDnsExists(Project project) throws Exception {
assertResourceRecordSetMatch(GCR_CNAME_RECORD, cnameRecordSet);
}

private void assertGarDnsExists(Project project) throws Exception {
String projectId = project.getProjectId();

ManagedZone managedZone = dnsCow.managedZones().get(projectId, GAR_MANAGED_ZONE_NAME).execute();
Map<String, ResourceRecordSet> resourceRecordSets =
dnsCow
.resourceRecordSets()
.list(project.getProjectId(), GAR_MANAGED_ZONE_NAME)
.execute()
.getRrsets()
.stream()
.collect(Collectors.toMap(ResourceRecordSet::getType, r -> r));
ResourceRecordSet aRecordSet = resourceRecordSets.get(GAR_A_RECORD.getType());
ResourceRecordSet cnameRecordSet = resourceRecordSets.get(GAR_CNAME_RECORD.getType());

assertEquals(GAR_MANAGED_ZONE_TEMPLATE.getName(), managedZone.getName());
assertEquals(
GAR_MANAGED_ZONE_TEMPLATE.getVisibility(), managedZone.getVisibility().toLowerCase());
assertEquals(GAR_MANAGED_ZONE_TEMPLATE.getDescription(), managedZone.getDescription());
assertResourceRecordSetMatch(GAR_A_RECORD, aRecordSet);
assertResourceRecordSetMatch(GAR_CNAME_RECORD, cnameRecordSet);
}

private void assertDnsNotExists(Project project) throws Exception {
assertFalse(
resourceExists(
Expand Down

0 comments on commit a59f323

Please sign in to comment.