1
0
mirror of https://github.com/google/nomulus synced 2025-12-23 14:25:44 +00:00

Save Cloud SQL connection names in Keyring (#2622)

This eliminates the need to make a new release after database disaster
recovery.
This commit is contained in:
Weimin Yu
2024-12-13 11:18:15 -05:00
committed by GitHub
parent f9d2839590
commit e5ebc5a2bb
10 changed files with 95 additions and 9 deletions

View File

@@ -124,7 +124,9 @@ public abstract class DummyKeyringModule {
"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() {}

View File

@@ -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,
@@ -55,7 +57,9 @@ public final class InMemoryKeyring implements Keyring {
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(),
@@ -81,6 +85,8 @@ public final class InMemoryKeyring implements Keyring {
this.marksdbSmdrlLoginAndPassword =
checkNotNull(marksdbSmdrlLoginAndPassword, "marksdbSmdrlLoginAndPassword");
this.bsaApiKey = checkNotNull(bsaApiKey, "bsaApiKey");
this.sqlPrimaryConnectionName = sqlPrimaryConnectionName;
this.sqlReplicaConnectionName = sqlReplicaConnectionName;
}
@Override
@@ -153,6 +159,16 @@ public final class InMemoryKeyring implements Keyring {
return bsaApiKey;
}
@Override
public String getSqlPrimaryConnectionName() {
return sqlPrimaryConnectionName;
}
@Override
public String getSqlReplicaConnectionName() {
return sqlReplicaConnectionName;
}
/** Does nothing. */
@Override
public void close() {}

View File

@@ -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();

View File

@@ -57,14 +57,16 @@ public class SecretManagerKeyring implements Keyring {
/** 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());
@@ -148,6 +150,16 @@ public class SecretManagerKeyring implements Keyring {
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() {}

View File

@@ -32,6 +32,8 @@ import static google.registry.keyring.secretmanager.SecretManagerKeyring.StringK
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;
@@ -124,6 +126,14 @@ public final class SecretManagerKeyringUpdater {
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.
*

View File

@@ -64,8 +64,6 @@ final class GetKeyringSecretCommand implements Command {
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 ->
@@ -91,6 +89,12 @@ final class GetKeyringSecretCommand implements Command {
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()));
}
}
}

View File

@@ -90,12 +90,16 @@ final class UpdateKeyringSecretCommand implements Command {
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();

View File

@@ -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
}

View File

@@ -102,6 +102,24 @@ public class SecretManagerKeyringUpdaterTest {
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";

View File

@@ -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() {
@@ -151,6 +153,16 @@ public final class FakeKeyringModule {
return rdeReceiverKey;
}
@Override
public String getSqlPrimaryConnectionName() {
return SQL_PRIMARY_CONNECTION;
}
@Override
public String getSqlReplicaConnectionName() {
return SQL_REPLICA_CONNECTION;
}
@Override
public void close() {}
};