Skip to content

Commit

Permalink
Save Cloud SQL connection names in Keyring (#2622)
Browse files Browse the repository at this point in the history
This eliminates the need to make a new release after database disaster
recovery.
  • Loading branch information
weiminyu authored Dec 13, 2024
1 parent f9d2839 commit e5ebc5a
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ static InMemoryKeyring provideDummyKeyring() {
"not a real login",
"not a real credential",
"not a real password",
"not a real password");
"not a real password",
"not the real primary connection",
"not the real replica connection");
}

private DummyKeyringModule() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public final class InMemoryKeyring implements Keyring {
private final String marksdbLordnPassword;
private final String marksdbSmdrlLoginAndPassword;
private final String bsaApiKey;
private final String sqlPrimaryConnectionName;
private final String sqlReplicaConnectionName;

public InMemoryKeyring(
PGPKeyPair rdeStagingKey,
Expand All @@ -55,7 +57,9 @@ public InMemoryKeyring(
String marksdbSmdrlLoginAndPassword,
String cloudSqlPassword,
String toolsCloudSqlPassword,
String bsaApiKey) {
String bsaApiKey,
String sqlPrimaryConnectionName,
String sqlReplicaConnectionName) {
checkArgument(PgpHelper.isSigningKey(rdeSigningKey.getPublicKey()),
"RDE signing key must support signing: %s", rdeSigningKey.getKeyID());
checkArgument(rdeStagingKey.getPublicKey().isEncryptionKey(),
Expand All @@ -81,6 +85,8 @@ public InMemoryKeyring(
this.marksdbSmdrlLoginAndPassword =
checkNotNull(marksdbSmdrlLoginAndPassword, "marksdbSmdrlLoginAndPassword");
this.bsaApiKey = checkNotNull(bsaApiKey, "bsaApiKey");
this.sqlPrimaryConnectionName = sqlPrimaryConnectionName;
this.sqlReplicaConnectionName = sqlReplicaConnectionName;
}

@Override
Expand Down Expand Up @@ -153,6 +159,16 @@ public String getBsaApiKey() {
return bsaApiKey;
}

@Override
public String getSqlPrimaryConnectionName() {
return sqlPrimaryConnectionName;
}

@Override
public String getSqlReplicaConnectionName() {
return sqlReplicaConnectionName;
}

/** Does nothing. */
@Override
public void close() {}
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/java/google/registry/keyring/api/Keyring.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ public interface Keyring extends AutoCloseable {
/** Returns the API_KEY for authentication with the BSA portal. */
String getBsaApiKey();

/** Returns the Cloud SQL connection name of the primary database instance. */
String getSqlPrimaryConnectionName();

/** Returns the Cloud SQL connection name of the replica database instance. */
String getSqlReplicaConnectionName();

// Don't throw so try-with-resources works better.
@Override
void close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,16 @@ String getLabel() {

/** Key labels for string secrets. */
enum StringKeyLabel {
SAFE_BROWSING_API_KEY,
BSA_API_KEY_STRING,
ICANN_REPORTING_PASSWORD_STRING,
MARKSDB_DNL_LOGIN_STRING,
MARKSDB_LORDN_PASSWORD_STRING,
MARKSDB_SMDRL_LOGIN_STRING,
RDE_SSH_CLIENT_PRIVATE_STRING,
RDE_SSH_CLIENT_PUBLIC_STRING;
RDE_SSH_CLIENT_PUBLIC_STRING,
SAFE_BROWSING_API_KEY,
SQL_PRIMARY_CONN_NAME,
SQL_REPLICA_CONN_NAME;

String getLabel() {
return UPPER_UNDERSCORE.to(LOWER_HYPHEN, name());
Expand Down Expand Up @@ -148,6 +150,16 @@ public String getBsaApiKey() {
return getString(StringKeyLabel.BSA_API_KEY_STRING);
}

@Override
public String getSqlPrimaryConnectionName() {
return getString(StringKeyLabel.SQL_PRIMARY_CONN_NAME);
}

@Override
public String getSqlReplicaConnectionName() {
return getString(StringKeyLabel.SQL_REPLICA_CONN_NAME);
}

/** No persistent resources are maintained for this Keyring implementation. */
@Override
public void close() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import static google.registry.keyring.secretmanager.SecretManagerKeyring.StringKeyLabel.RDE_SSH_CLIENT_PRIVATE_STRING;
import static google.registry.keyring.secretmanager.SecretManagerKeyring.StringKeyLabel.RDE_SSH_CLIENT_PUBLIC_STRING;
import static google.registry.keyring.secretmanager.SecretManagerKeyring.StringKeyLabel.SAFE_BROWSING_API_KEY;
import static google.registry.keyring.secretmanager.SecretManagerKeyring.StringKeyLabel.SQL_PRIMARY_CONN_NAME;
import static google.registry.keyring.secretmanager.SecretManagerKeyring.StringKeyLabel.SQL_REPLICA_CONN_NAME;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;

import com.google.common.flogger.FluentLogger;
Expand Down Expand Up @@ -124,6 +126,14 @@ public SecretManagerKeyringUpdater setBsaApiKey(String credential) {
return setString(credential, BSA_API_KEY_STRING);
}

public SecretManagerKeyringUpdater setSqlPrimaryConnectionName(String name) {
return setString(name, SQL_PRIMARY_CONN_NAME);
}

public SecretManagerKeyringUpdater setSqlReplicaConnectionName(String name) {
return setString(name, SQL_REPLICA_CONN_NAME);
}

/**
* Persists the secrets in the Secret Manager.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ public void run() throws Exception {
case BSA_API_KEY -> out.write(KeySerializer.serializeString(keyring.getBsaApiKey()));
case ICANN_REPORTING_PASSWORD ->
out.write(KeySerializer.serializeString(keyring.getIcannReportingPassword()));
case SAFE_BROWSING_API_KEY ->
out.write(KeySerializer.serializeString(keyring.getSafeBrowsingAPIKey()));
case MARKSDB_DNL_LOGIN_AND_PASSWORD ->
out.write(KeySerializer.serializeString(keyring.getMarksdbDnlLoginAndPassword()));
case MARKSDB_LORDN_PASSWORD ->
Expand All @@ -91,6 +89,12 @@ public void run() throws Exception {
keyring.getRdeStagingEncryptionKey(), keyring.getRdeStagingDecryptionKey())));
case RDE_STAGING_PUBLIC_KEY ->
out.write(KeySerializer.serializePublicKey(keyring.getRdeStagingEncryptionKey()));
case SAFE_BROWSING_API_KEY ->
out.write(KeySerializer.serializeString(keyring.getSafeBrowsingAPIKey()));
case SQL_PRIMARY_CONN_NAME ->
out.write(KeySerializer.serializeString(keyring.getSqlPrimaryConnectionName()));
case SQL_REPLICA_CONN_NAME ->
out.write(KeySerializer.serializeString(keyring.getSqlReplicaConnectionName()));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,16 @@ public void run() throws Exception {
secretManagerKeyringUpdater.setRdeSshClientPublicKey(deserializeString(input));
case RDE_STAGING_KEY_PAIR ->
secretManagerKeyringUpdater.setRdeStagingKey(deserializeKeyPair(input));
case SAFE_BROWSING_API_KEY ->
secretManagerKeyringUpdater.setSafeBrowsingAPIKey(deserializeString(input));
case RDE_STAGING_PUBLIC_KEY ->
throw new IllegalArgumentException(
"Can't update RDE_STAGING_PUBLIC_KEY directly."
+ " Must update public and private keys together using RDE_STAGING_KEY_PAIR.");
case SAFE_BROWSING_API_KEY ->
secretManagerKeyringUpdater.setSafeBrowsingAPIKey(deserializeString(input));
case SQL_PRIMARY_CONN_NAME ->
secretManagerKeyringUpdater.setSqlPrimaryConnectionName(deserializeString(input));
case SQL_REPLICA_CONN_NAME ->
secretManagerKeyringUpdater.setSqlReplicaConnectionName(deserializeString(input));
}

secretManagerKeyringUpdater.update();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@ public enum KeyringKeyName {
RDE_SSH_CLIENT_PUBLIC_KEY,
RDE_STAGING_KEY_PAIR,
RDE_STAGING_PUBLIC_KEY,
SAFE_BROWSING_API_KEY
SAFE_BROWSING_API_KEY,
SQL_PRIMARY_CONN_NAME,
SQL_REPLICA_CONN_NAME
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,24 @@ void bsaApiKey() {
verifyPersistedSecret("bsa-api-key-string", secret);
}

@Test
void sqlPrimaryConnectionName() {
String name = "name";
updater.setSqlPrimaryConnectionName(name).update();

assertThat(keyring.getSqlPrimaryConnectionName()).isEqualTo(name);
verifyPersistedSecret("sql-primary-conn-name", name);
}

@Test
void sqlReplicaConnectionName() {
String name = "name";
updater.setSqlReplicaConnectionName(name).update();

assertThat(keyring.getSqlReplicaConnectionName()).isEqualTo(name);
verifyPersistedSecret("sql-replica-conn-name", name);
}

@Test
void marksdbDnlLoginAndPassword() {
String secret = "marksdbDnlLoginAndPassword";
Expand Down
12 changes: 12 additions & 0 deletions core/src/test/java/google/registry/testing/FakeKeyringModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ public final class FakeKeyringModule {
private static final String MARKSDB_LORDN_PASSWORD = "yolo";
private static final String MARKSDB_SMDRL_LOGIN_AND_PASSWORD = "smdrl:yolo";
private static final String BSA_API_KEY = "bsaapikey";
private static final String SQL_PRIMARY_CONNECTION = "project:primary-region:primary-name";
private static final String SQL_REPLICA_CONNECTION = "project:replica-region:replica-name";

@Provides
public Keyring get() {
Expand Down Expand Up @@ -151,6 +153,16 @@ public PGPPublicKey getBrdaReceiverKey() {
return rdeReceiverKey;
}

@Override
public String getSqlPrimaryConnectionName() {
return SQL_PRIMARY_CONNECTION;
}

@Override
public String getSqlReplicaConnectionName() {
return SQL_REPLICA_CONNECTION;
}

@Override
public void close() {}
};
Expand Down

0 comments on commit e5ebc5a

Please sign in to comment.