Read GCP proxy EPP SSL secret from GCS

This allows us to not ship the proxy with certificates/private keys. The secret is still encrypted by KMS. Reading the secret only happens once when the first EPP request comes in, which should not incur any tangible performance penalty.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=191771680
This commit is contained in:
jianglai 2018-04-05 11:28:58 -07:00 committed by Ben McIlwain
parent 18a145eef1
commit 983bd27ee0
7 changed files with 55 additions and 12 deletions

View file

@ -27,6 +27,7 @@ java_library(
"@com_google_api_client",
"@com_google_apis_google_api_services_cloudkms",
"@com_google_apis_google_api_services_monitoring",
"@com_google_apis_google_api_services_storage",
"@com_google_auto_value",
"@com_google_code_findbugs_jsr305",
"@com_google_dagger",

View file

@ -37,7 +37,7 @@ public class ProxyConfig {
public List<String> gcpScopes;
public int accessTokenValidPeriodSeconds;
public int accessTokenRefreshBeforeExpirySeconds;
public String sslPemFilename;
public Gcs gcs;
public Kms kms;
public Epp epp;
public Whois whois;
@ -45,6 +45,12 @@ public class ProxyConfig {
public HttpsRelay httpsRelay;
public Metrics metrics;
/** Configuration options that apply to GCS. */
public static class Gcs {
public String bucket;
public String sslPemFilename;
}
/** Configuration options that apply to Cloud KMS. */
public static class Kms {
public String location;

View file

@ -16,7 +16,6 @@ package google.registry.proxy;
import static com.google.common.base.Suppliers.memoizeWithExpiration;
import static google.registry.proxy.ProxyConfig.getProxyConfig;
import static google.registry.util.ResourceUtils.readResourceBytes;
import static java.util.concurrent.TimeUnit.SECONDS;
import com.beust.jcommander.JCommander;
@ -26,6 +25,7 @@ import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.util.Utils;
import com.google.api.services.cloudkms.v1.CloudKMS;
import com.google.api.services.cloudkms.v1.model.DecryptRequest;
import com.google.api.services.storage.Storage;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.monitoring.metrics.MetricReporter;
@ -44,6 +44,7 @@ import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.OpenSsl;
import io.netty.handler.ssl.SslProvider;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Optional;
@ -218,14 +219,32 @@ public class ProxyModule {
.build();
}
@Singleton
@Provides
static Storage provideStorage(GoogleCredential credential, ProxyConfig config) {
return new Storage.Builder(
Utils.getDefaultTransport(), Utils.getDefaultJsonFactory(), credential)
.setApplicationName(config.projectId)
.build();
}
@Singleton
@Provides
@Named("encryptedPemBytes")
static byte[] provideEncryptedPemBytes(ProxyConfig config) {
static byte[] provideEncryptedPemBytes(Storage storage, ProxyConfig config) {
try {
return readResourceBytes(ProxyModule.class, "resources/" + config.sslPemFilename).read();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
storage
.objects()
.get(config.gcs.bucket, config.gcs.sslPemFilename)
.executeMediaAndDownloadTo(outputStream);
return outputStream.toByteArray();
} catch (IOException e) {
logger.severefmt(e, "Error reading encrypted PEM file: %s", config.sslPemFilename);
logger.severefmt(
e,
"Error reading encrypted PEM file %s from GCS bucket %s",
config.gcs.sslPemFilename,
config.gcs.bucket);
throw new RuntimeException(e);
}
}

View file

@ -36,8 +36,11 @@ accessTokenValidPeriodSeconds: 1800
# com.google.api.client.auth.oauth2.Credential#intercept.
accessTokenRefreshBeforeExpirySeconds: 60
# Name of the encrypted PEM file.
sslPemFilename: your-ssl.pem
gcs:
# GCS bucket that stores the encrypted PEM file.
bucket: your-gcs-bucket
# Name of the encrypted PEM file.
sslPemFilename: your-pem-filename
# Strings used to construct the KMS crypto key URL.
# See: https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings.cryptoKeys

View file

@ -12,6 +12,7 @@ module "proxy" {
nomulus_project_name = "YOUR_NOMULUS_GPROJECT"
gcr_project_name = "YOUR_GCR_PROJECT"
proxy_domain_name = "YOUR_PROXY_DOMAIN"
proxy_certificate_bucket = "YOU_CERTIFICATE_BUCKET"
}
output "proxy_service_account_client_id" {

View file

@ -0,0 +1,10 @@
resource "google_storage_bucket" "proxy_certificate" {
name = "${var.proxy_certificate_bucket}"
storage_class = "MULTI_REGIONAL"
}
resource "google_storage_bucket_iam_member" "member" {
bucket = "${google_storage_bucket.proxy_certificate.name}"
role = "roles/storage.objectViewer"
member = "serviceAccount:${google_service_account.proxy_service_account.email}"
}

View file

@ -10,6 +10,9 @@ variable "gcr_project_name" {}
# The base domain name of the proxy, without the whois. or epp. part.
variable "proxy_domain_name" {}
# The GCS bucket that stores the encrypted SSL certificate.
variable "proxy_certificate_bucket" {}
# Cloud KMS keyring name
variable "proxy_key_ring" {
default = "proxy-key-ring"