mirror of
https://github.com/google/nomulus
synced 2026-01-03 03:35:42 +00:00
Make SecretManagerkeyring the only allowed keyring (#2636)
Remove the support for custom keyrings. There is no pressing use case, and can be error-prone.
This commit is contained in:
@@ -20,6 +20,7 @@ import dagger.Lazy;
|
|||||||
import google.registry.config.CredentialModule;
|
import google.registry.config.CredentialModule;
|
||||||
import google.registry.config.RegistryConfig.Config;
|
import google.registry.config.RegistryConfig.Config;
|
||||||
import google.registry.config.RegistryConfig.ConfigModule;
|
import google.registry.config.RegistryConfig.ConfigModule;
|
||||||
|
import google.registry.keyring.KeyringModule;
|
||||||
import google.registry.persistence.PersistenceModule;
|
import google.registry.persistence.PersistenceModule;
|
||||||
import google.registry.persistence.PersistenceModule.BeamJpaTm;
|
import google.registry.persistence.PersistenceModule.BeamJpaTm;
|
||||||
import google.registry.persistence.PersistenceModule.BeamReadOnlyReplicaJpaTm;
|
import google.registry.persistence.PersistenceModule.BeamReadOnlyReplicaJpaTm;
|
||||||
@@ -36,6 +37,7 @@ import javax.inject.Singleton;
|
|||||||
modules = {
|
modules = {
|
||||||
ConfigModule.class,
|
ConfigModule.class,
|
||||||
CredentialModule.class,
|
CredentialModule.class,
|
||||||
|
KeyringModule.class,
|
||||||
PersistenceModule.class,
|
PersistenceModule.class,
|
||||||
SecretManagerModule.class,
|
SecretManagerModule.class,
|
||||||
UtilsModule.class
|
UtilsModule.class
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ public class RegistryConfigSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Configuration for keyrings (used to store secrets outside of source). */
|
/** Configuration for keyrings (used to store secrets outside of source). */
|
||||||
|
// TODO(b/388835696): remove section after updating config files.
|
||||||
public static class Keyring {
|
public static class Keyring {
|
||||||
public String activeKeyring;
|
public String activeKeyring;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,31 +14,22 @@
|
|||||||
|
|
||||||
package google.registry.keyring;
|
package google.registry.keyring;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import dagger.Binds;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
import google.registry.config.RegistryConfig.Config;
|
import google.registry.config.RegistryConfig.Config;
|
||||||
import google.registry.keyring.api.Keyring;
|
import google.registry.keyring.api.Keyring;
|
||||||
import java.util.Map;
|
import google.registry.keyring.secretmanager.SecretManagerKeyring;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
/** Dagger module for {@link Keyring} */
|
/** Dagger module for {@link Keyring} */
|
||||||
@Module
|
@Module
|
||||||
public final class KeyringModule {
|
public abstract class KeyringModule {
|
||||||
|
|
||||||
@Provides
|
@Binds
|
||||||
@Singleton
|
@Singleton
|
||||||
public static Keyring provideKeyring(
|
public abstract Keyring provideKeyring(SecretManagerKeyring keyring);
|
||||||
Map<String, Keyring> keyrings, @Config("activeKeyring") String activeKeyring) {
|
|
||||||
checkState(
|
|
||||||
keyrings.containsKey(activeKeyring),
|
|
||||||
"Invalid Keyring %s is configured; valid choices are %s",
|
|
||||||
activeKeyring,
|
|
||||||
keyrings.keySet());
|
|
||||||
return keyrings.get(activeKeyring);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Config("cloudSqlInstanceConnectionName")
|
@Config("cloudSqlInstanceConnectionName")
|
||||||
|
|||||||
@@ -1,205 +0,0 @@
|
|||||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package google.registry.keyring.api;
|
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import com.google.common.base.MoreObjects;
|
|
||||||
import com.google.common.flogger.FluentLogger;
|
|
||||||
import google.registry.util.ComparingInvocationHandler;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Objects;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import org.bouncycastle.bcpg.BCPGKey;
|
|
||||||
import org.bouncycastle.bcpg.PublicKeyPacket;
|
|
||||||
import org.bouncycastle.openpgp.PGPKeyPair;
|
|
||||||
import org.bouncycastle.openpgp.PGPPrivateKey;
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks that a second keyring returns the same result as the current one.
|
|
||||||
*
|
|
||||||
* <p>Will behave exactly like the "actualKeyring" - as in will throw / return the exact same values
|
|
||||||
* - no matter what the "secondKeyring" does. But will log a warning if "secondKeyring" acts
|
|
||||||
* differently than "actualKeyring".
|
|
||||||
*
|
|
||||||
* <p>If both keyrings threw exceptions, there is no check whether the exeptions are the same. The
|
|
||||||
* assumption is that an error happened in both, but they might report that error differently.
|
|
||||||
*/
|
|
||||||
public final class ComparatorKeyring extends ComparingInvocationHandler<Keyring> {
|
|
||||||
|
|
||||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
|
||||||
|
|
||||||
private ComparatorKeyring(Keyring original, Keyring second) {
|
|
||||||
super(Keyring.class, original, second);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an instance of Keyring that is an exact proxy of "original".
|
|
||||||
*
|
|
||||||
* <p>This proxy will log any differences in return value or thrown exceptions with "second".
|
|
||||||
*/
|
|
||||||
public static Keyring create(Keyring original, Keyring second) {
|
|
||||||
return new ComparatorKeyring(original, second).makeProxy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void log(Method method, String message) {
|
|
||||||
logger.atSevere().log("ComparatorKeyring.%s: %s", method.getName(), message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Implements equals for the PGP classes. */
|
|
||||||
@Override
|
|
||||||
protected boolean compareResults(Method method, @Nullable Object a, @Nullable Object b) {
|
|
||||||
Class<?> clazz = method.getReturnType();
|
|
||||||
if (PGPPublicKey.class.equals(clazz)) {
|
|
||||||
return compare((PGPPublicKey) a, (PGPPublicKey) b);
|
|
||||||
}
|
|
||||||
if (PGPPrivateKey.class.equals(clazz)) {
|
|
||||||
return compare((PGPPrivateKey) a, (PGPPrivateKey) b);
|
|
||||||
}
|
|
||||||
if (PGPKeyPair.class.equals(clazz)) {
|
|
||||||
return compare((PGPKeyPair) a, (PGPKeyPair) b);
|
|
||||||
}
|
|
||||||
return super.compareResults(method, a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Implements toString for the PGP classes. */
|
|
||||||
@Override
|
|
||||||
protected String stringifyResult(Method method, @Nullable Object a) {
|
|
||||||
Class<?> clazz = method.getReturnType();
|
|
||||||
if (PGPPublicKey.class.equals(clazz)) {
|
|
||||||
return stringify((PGPPublicKey) a);
|
|
||||||
}
|
|
||||||
if (PGPPrivateKey.class.equals(clazz)) {
|
|
||||||
return stringify((PGPPrivateKey) a);
|
|
||||||
}
|
|
||||||
if (PGPKeyPair.class.equals(clazz)) {
|
|
||||||
return stringify((PGPKeyPair) a);
|
|
||||||
}
|
|
||||||
return super.stringifyResult(method, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String stringifyThrown(Method method, Throwable throwable) {
|
|
||||||
StringWriter stringWriter = new StringWriter();
|
|
||||||
PrintWriter printWriter = new PrintWriter(stringWriter);
|
|
||||||
throwable.printStackTrace(printWriter);
|
|
||||||
return String.format("%s\nStack trace:\n%s", throwable.toString(), stringWriter.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// .equals implementation for PGP types.
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static boolean compare(@Nullable PGPKeyPair a, @Nullable PGPKeyPair b) {
|
|
||||||
if (a == null || b == null) {
|
|
||||||
return a == null && b == null;
|
|
||||||
}
|
|
||||||
return compare(a.getPublicKey(), b.getPublicKey())
|
|
||||||
&& compare(a.getPrivateKey(), b.getPrivateKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static boolean compare(@Nullable PGPPublicKey a, @Nullable PGPPublicKey b) {
|
|
||||||
if (a == null || b == null) {
|
|
||||||
return a == null && b == null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return Arrays.equals(a.getFingerprint(), b.getFingerprint())
|
|
||||||
&& Arrays.equals(a.getEncoded(), b.getEncoded());
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.atSevere().withCause(e).log(
|
|
||||||
"ComparatorKeyring error: PGPPublicKey.getEncoded failed.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static boolean compare(@Nullable PGPPrivateKey a, @Nullable PGPPrivateKey b) {
|
|
||||||
if (a == null || b == null) {
|
|
||||||
return a == null && b == null;
|
|
||||||
}
|
|
||||||
return a.getKeyID() == b.getKeyID()
|
|
||||||
&& compare(a.getPrivateKeyDataPacket(), b.getPrivateKeyDataPacket())
|
|
||||||
&& compare(a.getPublicKeyPacket(), b.getPublicKeyPacket());
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static boolean compare(PublicKeyPacket a, PublicKeyPacket b) {
|
|
||||||
if (a == null || b == null) {
|
|
||||||
return a == null && b == null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return Arrays.equals(a.getEncoded(), b.getEncoded());
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.atSevere().withCause(e).log(
|
|
||||||
"ComparatorKeyring error: PublicKeyPacket.getEncoded failed.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static boolean compare(BCPGKey a, BCPGKey b) {
|
|
||||||
if (a == null || b == null) {
|
|
||||||
return a == null && b == null;
|
|
||||||
}
|
|
||||||
return Objects.equals(a.getFormat(), b.getFormat())
|
|
||||||
&& Arrays.equals(a.getEncoded(), b.getEncoded());
|
|
||||||
}
|
|
||||||
|
|
||||||
// toString implementations
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static String stringify(PGPKeyPair a) {
|
|
||||||
if (a == null) {
|
|
||||||
return "null";
|
|
||||||
}
|
|
||||||
return MoreObjects.toStringHelper(PGPKeyPair.class)
|
|
||||||
.addValue(stringify(a.getPublicKey()))
|
|
||||||
.addValue(stringify(a.getPrivateKey()))
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static String stringify(PGPPublicKey a) {
|
|
||||||
if (a == null) {
|
|
||||||
return "null";
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
for (byte b : a.getFingerprint()) {
|
|
||||||
builder.append(String.format("%02x:", b));
|
|
||||||
}
|
|
||||||
return MoreObjects.toStringHelper(PGPPublicKey.class)
|
|
||||||
.add("fingerprint", builder.toString())
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static String stringify(PGPPrivateKey a) {
|
|
||||||
if (a == null) {
|
|
||||||
return "null";
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to be careful what information we output here. The private key should be private, and
|
|
||||||
// I'm not sure what is safe to put in the logs.
|
|
||||||
return MoreObjects.toStringHelper(PGPPrivateKey.class)
|
|
||||||
.add("keyId", a.getKeyID())
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package google.registry.keyring.api;
|
|
||||||
|
|
||||||
import static com.google.common.io.Resources.getResource;
|
|
||||||
import static google.registry.keyring.api.PgpHelper.KeyRequirement.ENCRYPT_SIGN;
|
|
||||||
import static google.registry.keyring.api.PgpHelper.lookupKeyPair;
|
|
||||||
|
|
||||||
import com.google.common.base.VerifyException;
|
|
||||||
import com.google.common.io.ByteSource;
|
|
||||||
import com.google.common.io.Resources;
|
|
||||||
import dagger.Binds;
|
|
||||||
import dagger.Module;
|
|
||||||
import dagger.Provides;
|
|
||||||
import dagger.multibindings.IntoMap;
|
|
||||||
import dagger.multibindings.StringKey;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
import javax.inject.Named;
|
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
|
||||||
import org.bouncycastle.openpgp.PGPKeyPair;
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
|
||||||
import org.bouncycastle.openpgp.PGPUtil;
|
|
||||||
import org.bouncycastle.openpgp.bc.BcPGPPublicKeyRingCollection;
|
|
||||||
import org.bouncycastle.openpgp.bc.BcPGPSecretKeyRingCollection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dagger keyring module that provides an {@link InMemoryKeyring} instance populated with dummy
|
|
||||||
* values.
|
|
||||||
*
|
|
||||||
* <p>This dummy module allows the domain registry code to compile and run in an unmodified state,
|
|
||||||
* with all attempted outgoing connections failing because the supplied dummy credentials aren't
|
|
||||||
* valid. For a real system that needs to connect with external services, you should replace this
|
|
||||||
* module with one that loads real credentials from secure sources.
|
|
||||||
*
|
|
||||||
* <p>The dummy PGP keyrings are created using gnupg1/pgp1 roughly like the following (using
|
|
||||||
* gnupg2/pgp2 is an exercise left for the developer):
|
|
||||||
*
|
|
||||||
* <pre>{@code
|
|
||||||
* # mkdir gpg
|
|
||||||
* # chmod 700 gpg
|
|
||||||
* # gpg1 --homedir gpg --gen-key <<<EOF
|
|
||||||
* 1
|
|
||||||
* 1024
|
|
||||||
* 0
|
|
||||||
* Y
|
|
||||||
* Test Registry
|
|
||||||
* test-registry@example.com
|
|
||||||
*
|
|
||||||
* O
|
|
||||||
* EOF
|
|
||||||
* [press enter twice at keyring password prompts]
|
|
||||||
* # gpg1 --homedir gpg -a -o pgp-public-keyring.asc --export test-registry@example.com
|
|
||||||
* # gpg1 --homedir gpg -a -o pgp-private-keyring.asc --export-secret-keys test-registry@example.com
|
|
||||||
* # mv pgp*keyring.asc java/google/registry/keyring/api
|
|
||||||
* # rm -rf gpg
|
|
||||||
* }</pre>
|
|
||||||
*/
|
|
||||||
@Module
|
|
||||||
@Immutable
|
|
||||||
public abstract class DummyKeyringModule {
|
|
||||||
|
|
||||||
public static final String NAME = "Dummy";
|
|
||||||
|
|
||||||
/** The contents of a dummy PGP public key stored in a file. */
|
|
||||||
private static final ByteSource PGP_PUBLIC_KEYRING =
|
|
||||||
Resources.asByteSource(getResource(InMemoryKeyring.class, "pgp-public-keyring.asc"));
|
|
||||||
|
|
||||||
/** The contents of a dummy PGP private key stored in a file. */
|
|
||||||
private static final ByteSource PGP_PRIVATE_KEYRING =
|
|
||||||
Resources.asByteSource(getResource(InMemoryKeyring.class, "pgp-private-keyring.asc"));
|
|
||||||
|
|
||||||
/** The email address of the aforementioned PGP key. */
|
|
||||||
private static final String EMAIL_ADDRESS = "test-registry@example.com";
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
@IntoMap
|
|
||||||
@StringKey(NAME)
|
|
||||||
abstract Keyring provideKeyring(@Named("DummyKeyring") InMemoryKeyring keyring);
|
|
||||||
|
|
||||||
/** Always returns a {@link InMemoryKeyring} instance. */
|
|
||||||
@Provides
|
|
||||||
@Named("DummyKeyring")
|
|
||||||
static InMemoryKeyring provideDummyKeyring() {
|
|
||||||
PGPKeyPair dummyKey;
|
|
||||||
try (InputStream publicInput = PGP_PUBLIC_KEYRING.openStream();
|
|
||||||
InputStream privateInput = PGP_PRIVATE_KEYRING.openStream()) {
|
|
||||||
PGPPublicKeyRingCollection publicKeys =
|
|
||||||
new BcPGPPublicKeyRingCollection(PGPUtil.getDecoderStream(publicInput));
|
|
||||||
PGPSecretKeyRingCollection privateKeys =
|
|
||||||
new BcPGPSecretKeyRingCollection(PGPUtil.getDecoderStream(privateInput));
|
|
||||||
dummyKey = lookupKeyPair(publicKeys, privateKeys, EMAIL_ADDRESS, ENCRYPT_SIGN);
|
|
||||||
} catch (PGPException | IOException e) {
|
|
||||||
throw new VerifyException("Failed to load PGP keys from jar", e);
|
|
||||||
}
|
|
||||||
// Use the same dummy PGP keypair for all required PGP keys -- a real production system would
|
|
||||||
// have different values for these keys. Pass dummy values for all Strings.
|
|
||||||
return new InMemoryKeyring(
|
|
||||||
dummyKey,
|
|
||||||
dummyKey,
|
|
||||||
dummyKey.getPublicKey(),
|
|
||||||
dummyKey,
|
|
||||||
dummyKey.getPublicKey(),
|
|
||||||
"not a real key",
|
|
||||||
"not a real key",
|
|
||||||
"not a real password",
|
|
||||||
"not a real API key",
|
|
||||||
"not a real login",
|
|
||||||
"not a real password",
|
|
||||||
"not a real login",
|
|
||||||
"not a real credential",
|
|
||||||
"not a real password",
|
|
||||||
"not a real password",
|
|
||||||
"not the real primary connection",
|
|
||||||
"not the real replica connection");
|
|
||||||
}
|
|
||||||
|
|
||||||
private DummyKeyringModule() {}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package google.registry.keyring.api;
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
import org.bouncycastle.openpgp.PGPKeyPair;
|
|
||||||
import org.bouncycastle.openpgp.PGPPrivateKey;
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
|
||||||
|
|
||||||
/** A {@link Keyring} that uses in-memory values for all credentials. */
|
|
||||||
@Immutable
|
|
||||||
public final class InMemoryKeyring implements Keyring {
|
|
||||||
|
|
||||||
private final PGPKeyPair rdeStagingKey;
|
|
||||||
private final PGPKeyPair rdeSigningKey;
|
|
||||||
private final PGPPublicKey rdeReceiverKey;
|
|
||||||
private final PGPKeyPair brdaSigningKey;
|
|
||||||
private final PGPPublicKey brdaEncryptionKey;
|
|
||||||
private final String rdeSshClientPublicKey;
|
|
||||||
private final String rdeSshClientPrivateKey;
|
|
||||||
private final String icannReportingPassword;
|
|
||||||
private final String safeBrowsingAPIKey;
|
|
||||||
private final String marksdbDnlLoginAndPassword;
|
|
||||||
private final String marksdbLordnPassword;
|
|
||||||
private final String marksdbSmdrlLoginAndPassword;
|
|
||||||
private final String bsaApiKey;
|
|
||||||
private final String sqlPrimaryConnectionName;
|
|
||||||
private final String sqlReplicaConnectionName;
|
|
||||||
|
|
||||||
public InMemoryKeyring(
|
|
||||||
PGPKeyPair rdeStagingKey,
|
|
||||||
PGPKeyPair rdeSigningKey,
|
|
||||||
PGPPublicKey rdeReceiverKey,
|
|
||||||
PGPKeyPair brdaSigningKey,
|
|
||||||
PGPPublicKey brdaEncryptionKey,
|
|
||||||
String rdeSshClientPublicKey,
|
|
||||||
String rdeSshClientPrivateKey,
|
|
||||||
String icannReportingPassword,
|
|
||||||
String safeBrowsingAPIKey,
|
|
||||||
String marksdbDnlLoginAndPassword,
|
|
||||||
String marksdbLordnPassword,
|
|
||||||
String marksdbSmdrlLoginAndPassword,
|
|
||||||
String cloudSqlPassword,
|
|
||||||
String toolsCloudSqlPassword,
|
|
||||||
String bsaApiKey,
|
|
||||||
String sqlPrimaryConnectionName,
|
|
||||||
String sqlReplicaConnectionName) {
|
|
||||||
checkArgument(PgpHelper.isSigningKey(rdeSigningKey.getPublicKey()),
|
|
||||||
"RDE signing key must support signing: %s", rdeSigningKey.getKeyID());
|
|
||||||
checkArgument(rdeStagingKey.getPublicKey().isEncryptionKey(),
|
|
||||||
"staging key must support encryption: %s", rdeStagingKey.getKeyID());
|
|
||||||
checkArgument(rdeReceiverKey.isEncryptionKey(),
|
|
||||||
"receiver key must support encryption: %s", rdeReceiverKey.getKeyID());
|
|
||||||
checkArgument(PgpHelper.isSigningKey(brdaSigningKey.getPublicKey()),
|
|
||||||
"BRDA signing key must support signing: %s", brdaSigningKey.getKeyID());
|
|
||||||
checkArgument(brdaEncryptionKey.isEncryptionKey(),
|
|
||||||
"encryption key must support encryption: %s", brdaEncryptionKey.getKeyID());
|
|
||||||
this.rdeStagingKey = rdeStagingKey;
|
|
||||||
this.rdeSigningKey = rdeSigningKey;
|
|
||||||
this.rdeReceiverKey = rdeReceiverKey;
|
|
||||||
this.brdaSigningKey = brdaSigningKey;
|
|
||||||
this.brdaEncryptionKey = brdaEncryptionKey;
|
|
||||||
this.rdeSshClientPublicKey = checkNotNull(rdeSshClientPublicKey, "rdeSshClientPublicKey");
|
|
||||||
this.rdeSshClientPrivateKey = checkNotNull(rdeSshClientPrivateKey, "rdeSshClientPrivateKey");
|
|
||||||
this.icannReportingPassword = checkNotNull(icannReportingPassword, "icannReportingPassword");
|
|
||||||
this.safeBrowsingAPIKey = checkNotNull(safeBrowsingAPIKey, "safeBrowsingAPIKey");
|
|
||||||
this.marksdbDnlLoginAndPassword =
|
|
||||||
checkNotNull(marksdbDnlLoginAndPassword, "marksdbDnlLoginAndPassword");
|
|
||||||
this.marksdbLordnPassword = checkNotNull(marksdbLordnPassword, "marksdbLordnPassword");
|
|
||||||
this.marksdbSmdrlLoginAndPassword =
|
|
||||||
checkNotNull(marksdbSmdrlLoginAndPassword, "marksdbSmdrlLoginAndPassword");
|
|
||||||
this.bsaApiKey = checkNotNull(bsaApiKey, "bsaApiKey");
|
|
||||||
this.sqlPrimaryConnectionName = sqlPrimaryConnectionName;
|
|
||||||
this.sqlReplicaConnectionName = sqlReplicaConnectionName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PGPKeyPair getRdeSigningKey() {
|
|
||||||
return rdeSigningKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PGPPublicKey getRdeStagingEncryptionKey() {
|
|
||||||
return rdeStagingKey.getPublicKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PGPPrivateKey getRdeStagingDecryptionKey() {
|
|
||||||
return rdeStagingKey.getPrivateKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PGPPublicKey getRdeReceiverKey() {
|
|
||||||
return rdeReceiverKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PGPKeyPair getBrdaSigningKey() {
|
|
||||||
return brdaSigningKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PGPPublicKey getBrdaReceiverKey() {
|
|
||||||
return brdaEncryptionKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getRdeSshClientPublicKey() {
|
|
||||||
return rdeSshClientPublicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getRdeSshClientPrivateKey() {
|
|
||||||
return rdeSshClientPrivateKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getIcannReportingPassword() {
|
|
||||||
return icannReportingPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSafeBrowsingAPIKey() {
|
|
||||||
return safeBrowsingAPIKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMarksdbDnlLoginAndPassword() {
|
|
||||||
return marksdbDnlLoginAndPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMarksdbLordnPassword() {
|
|
||||||
return marksdbLordnPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMarksdbSmdrlLoginAndPassword() {
|
|
||||||
return marksdbSmdrlLoginAndPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getBsaApiKey() {
|
|
||||||
return bsaApiKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSqlPrimaryConnectionName() {
|
|
||||||
return sqlPrimaryConnectionName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSqlReplicaConnectionName() {
|
|
||||||
return sqlReplicaConnectionName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Does nothing. */
|
|
||||||
@Override
|
|
||||||
public void close() {}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package google.registry.keyring.secretmanager;
|
|
||||||
|
|
||||||
import dagger.Binds;
|
|
||||||
import dagger.Module;
|
|
||||||
import dagger.multibindings.IntoMap;
|
|
||||||
import dagger.multibindings.StringKey;
|
|
||||||
import google.registry.keyring.api.Keyring;
|
|
||||||
|
|
||||||
/** Dagger module for {@link Keyring} backed by the Cloud SecretManager. */
|
|
||||||
@Module
|
|
||||||
public abstract class SecretManagerKeyringModule {
|
|
||||||
|
|
||||||
public static final String NAME = "CSM";
|
|
||||||
// TODO(b/257276342): Remove after configs in nomulus-internal are updated.
|
|
||||||
public static final String DEPRECATED_NAME = "KMS";
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
@IntoMap
|
|
||||||
@StringKey(DEPRECATED_NAME)
|
|
||||||
abstract Keyring provideDeprecatedKeyring(SecretManagerKeyring keyring);
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
@IntoMap
|
|
||||||
@StringKey(NAME)
|
|
||||||
abstract Keyring provideKeyring(SecretManagerKeyring keyring);
|
|
||||||
}
|
|
||||||
@@ -35,9 +35,7 @@ import google.registry.groups.GmailModule;
|
|||||||
import google.registry.groups.GroupsModule;
|
import google.registry.groups.GroupsModule;
|
||||||
import google.registry.groups.GroupssettingsModule;
|
import google.registry.groups.GroupssettingsModule;
|
||||||
import google.registry.keyring.KeyringModule;
|
import google.registry.keyring.KeyringModule;
|
||||||
import google.registry.keyring.api.DummyKeyringModule;
|
|
||||||
import google.registry.keyring.api.KeyModule;
|
import google.registry.keyring.api.KeyModule;
|
||||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
|
||||||
import google.registry.module.RegistryComponent.RegistryModule;
|
import google.registry.module.RegistryComponent.RegistryModule;
|
||||||
import google.registry.module.RequestComponent.RequestComponentModule;
|
import google.registry.module.RequestComponent.RequestComponentModule;
|
||||||
import google.registry.monitoring.whitebox.StackdriverModule;
|
import google.registry.monitoring.whitebox.StackdriverModule;
|
||||||
@@ -69,7 +67,6 @@ import javax.inject.Singleton;
|
|||||||
CustomLogicFactoryModule.class,
|
CustomLogicFactoryModule.class,
|
||||||
DirectoryModule.class,
|
DirectoryModule.class,
|
||||||
DriveModule.class,
|
DriveModule.class,
|
||||||
DummyKeyringModule.class,
|
|
||||||
GmailModule.class,
|
GmailModule.class,
|
||||||
GroupsModule.class,
|
GroupsModule.class,
|
||||||
GroupssettingsModule.class,
|
GroupssettingsModule.class,
|
||||||
@@ -81,7 +78,6 @@ import javax.inject.Singleton;
|
|||||||
PersistenceModule.class,
|
PersistenceModule.class,
|
||||||
RegistryModule.class,
|
RegistryModule.class,
|
||||||
RequestComponentModule.class,
|
RequestComponentModule.class,
|
||||||
SecretManagerKeyringModule.class,
|
|
||||||
SecretManagerModule.class,
|
SecretManagerModule.class,
|
||||||
ServerTridProviderModule.class,
|
ServerTridProviderModule.class,
|
||||||
SheetsServiceModule.class,
|
SheetsServiceModule.class,
|
||||||
|
|||||||
@@ -32,9 +32,7 @@ import google.registry.groups.GmailModule;
|
|||||||
import google.registry.groups.GroupsModule;
|
import google.registry.groups.GroupsModule;
|
||||||
import google.registry.groups.GroupssettingsModule;
|
import google.registry.groups.GroupssettingsModule;
|
||||||
import google.registry.keyring.KeyringModule;
|
import google.registry.keyring.KeyringModule;
|
||||||
import google.registry.keyring.api.DummyKeyringModule;
|
|
||||||
import google.registry.keyring.api.KeyModule;
|
import google.registry.keyring.api.KeyModule;
|
||||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
|
||||||
import google.registry.module.backend.BackendRequestComponent.BackendRequestComponentModule;
|
import google.registry.module.backend.BackendRequestComponent.BackendRequestComponentModule;
|
||||||
import google.registry.monitoring.whitebox.StackdriverModule;
|
import google.registry.monitoring.whitebox.StackdriverModule;
|
||||||
import google.registry.persistence.PersistenceModule;
|
import google.registry.persistence.PersistenceModule;
|
||||||
@@ -60,7 +58,6 @@ import javax.inject.Singleton;
|
|||||||
CredentialModule.class,
|
CredentialModule.class,
|
||||||
CustomLogicFactoryModule.class,
|
CustomLogicFactoryModule.class,
|
||||||
DirectoryModule.class,
|
DirectoryModule.class,
|
||||||
DummyKeyringModule.class,
|
|
||||||
DriveModule.class,
|
DriveModule.class,
|
||||||
GmailModule.class,
|
GmailModule.class,
|
||||||
GroupsModule.class,
|
GroupsModule.class,
|
||||||
@@ -71,7 +68,6 @@ import javax.inject.Singleton;
|
|||||||
KeyringModule.class,
|
KeyringModule.class,
|
||||||
NetHttpTransportModule.class,
|
NetHttpTransportModule.class,
|
||||||
PersistenceModule.class,
|
PersistenceModule.class,
|
||||||
SecretManagerKeyringModule.class,
|
|
||||||
SecretManagerModule.class,
|
SecretManagerModule.class,
|
||||||
ServerTridProviderModule.class,
|
ServerTridProviderModule.class,
|
||||||
SheetsServiceModule.class,
|
SheetsServiceModule.class,
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import google.registry.config.CredentialModule;
|
|||||||
import google.registry.config.RegistryConfig.ConfigModule;
|
import google.registry.config.RegistryConfig.ConfigModule;
|
||||||
import google.registry.groups.GmailModule;
|
import google.registry.groups.GmailModule;
|
||||||
import google.registry.keyring.KeyringModule;
|
import google.registry.keyring.KeyringModule;
|
||||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
|
||||||
import google.registry.module.bsa.BsaRequestComponent.BsaRequestComponentModule;
|
import google.registry.module.bsa.BsaRequestComponent.BsaRequestComponentModule;
|
||||||
import google.registry.monitoring.whitebox.StackdriverModule;
|
import google.registry.monitoring.whitebox.StackdriverModule;
|
||||||
import google.registry.persistence.PersistenceModule;
|
import google.registry.persistence.PersistenceModule;
|
||||||
@@ -43,7 +42,6 @@ import javax.inject.Singleton;
|
|||||||
GsonModule.class,
|
GsonModule.class,
|
||||||
PersistenceModule.class,
|
PersistenceModule.class,
|
||||||
KeyringModule.class,
|
KeyringModule.class,
|
||||||
SecretManagerKeyringModule.class,
|
|
||||||
SecretManagerModule.class,
|
SecretManagerModule.class,
|
||||||
StackdriverModule.class,
|
StackdriverModule.class,
|
||||||
UrlConnectionServiceModule.class,
|
UrlConnectionServiceModule.class,
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ import google.registry.groups.GmailModule;
|
|||||||
import google.registry.groups.GroupsModule;
|
import google.registry.groups.GroupsModule;
|
||||||
import google.registry.groups.GroupssettingsModule;
|
import google.registry.groups.GroupssettingsModule;
|
||||||
import google.registry.keyring.KeyringModule;
|
import google.registry.keyring.KeyringModule;
|
||||||
import google.registry.keyring.api.DummyKeyringModule;
|
|
||||||
import google.registry.keyring.api.KeyModule;
|
import google.registry.keyring.api.KeyModule;
|
||||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
|
||||||
import google.registry.module.frontend.FrontendRequestComponent.FrontendRequestComponentModule;
|
import google.registry.module.frontend.FrontendRequestComponent.FrontendRequestComponentModule;
|
||||||
import google.registry.monitoring.whitebox.StackdriverModule;
|
import google.registry.monitoring.whitebox.StackdriverModule;
|
||||||
import google.registry.privileges.secretmanager.SecretManagerModule;
|
import google.registry.privileges.secretmanager.SecretManagerModule;
|
||||||
@@ -52,7 +50,6 @@ import javax.inject.Singleton;
|
|||||||
CustomLogicFactoryModule.class,
|
CustomLogicFactoryModule.class,
|
||||||
CloudTasksUtilsModule.class,
|
CloudTasksUtilsModule.class,
|
||||||
DirectoryModule.class,
|
DirectoryModule.class,
|
||||||
DummyKeyringModule.class,
|
|
||||||
FrontendRequestComponentModule.class,
|
FrontendRequestComponentModule.class,
|
||||||
GmailModule.class,
|
GmailModule.class,
|
||||||
GroupsModule.class,
|
GroupsModule.class,
|
||||||
@@ -61,7 +58,6 @@ import javax.inject.Singleton;
|
|||||||
KeyModule.class,
|
KeyModule.class,
|
||||||
KeyringModule.class,
|
KeyringModule.class,
|
||||||
NetHttpTransportModule.class,
|
NetHttpTransportModule.class,
|
||||||
SecretManagerKeyringModule.class,
|
|
||||||
SecretManagerModule.class,
|
SecretManagerModule.class,
|
||||||
ServerTridProviderModule.class,
|
ServerTridProviderModule.class,
|
||||||
StackdriverModule.class,
|
StackdriverModule.class,
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ import google.registry.groups.DirectoryModule;
|
|||||||
import google.registry.groups.GroupsModule;
|
import google.registry.groups.GroupsModule;
|
||||||
import google.registry.groups.GroupssettingsModule;
|
import google.registry.groups.GroupssettingsModule;
|
||||||
import google.registry.keyring.KeyringModule;
|
import google.registry.keyring.KeyringModule;
|
||||||
import google.registry.keyring.api.DummyKeyringModule;
|
|
||||||
import google.registry.keyring.api.KeyModule;
|
import google.registry.keyring.api.KeyModule;
|
||||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
|
||||||
import google.registry.module.pubapi.PubApiRequestComponent.PubApiRequestComponentModule;
|
import google.registry.module.pubapi.PubApiRequestComponent.PubApiRequestComponentModule;
|
||||||
import google.registry.monitoring.whitebox.StackdriverModule;
|
import google.registry.monitoring.whitebox.StackdriverModule;
|
||||||
import google.registry.persistence.PersistenceModule;
|
import google.registry.persistence.PersistenceModule;
|
||||||
@@ -47,7 +45,6 @@ import javax.inject.Singleton;
|
|||||||
CredentialModule.class,
|
CredentialModule.class,
|
||||||
CustomLogicFactoryModule.class,
|
CustomLogicFactoryModule.class,
|
||||||
DirectoryModule.class,
|
DirectoryModule.class,
|
||||||
DummyKeyringModule.class,
|
|
||||||
GroupsModule.class,
|
GroupsModule.class,
|
||||||
GroupssettingsModule.class,
|
GroupssettingsModule.class,
|
||||||
GsonModule.class,
|
GsonModule.class,
|
||||||
@@ -56,7 +53,6 @@ import javax.inject.Singleton;
|
|||||||
NetHttpTransportModule.class,
|
NetHttpTransportModule.class,
|
||||||
PersistenceModule.class,
|
PersistenceModule.class,
|
||||||
PubApiRequestComponentModule.class,
|
PubApiRequestComponentModule.class,
|
||||||
SecretManagerKeyringModule.class,
|
|
||||||
SecretManagerModule.class,
|
SecretManagerModule.class,
|
||||||
ServerTridProviderModule.class,
|
ServerTridProviderModule.class,
|
||||||
StackdriverModule.class,
|
StackdriverModule.class,
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ import google.registry.groups.DirectoryModule;
|
|||||||
import google.registry.groups.GroupsModule;
|
import google.registry.groups.GroupsModule;
|
||||||
import google.registry.groups.GroupssettingsModule;
|
import google.registry.groups.GroupssettingsModule;
|
||||||
import google.registry.keyring.KeyringModule;
|
import google.registry.keyring.KeyringModule;
|
||||||
import google.registry.keyring.api.DummyKeyringModule;
|
|
||||||
import google.registry.keyring.api.KeyModule;
|
import google.registry.keyring.api.KeyModule;
|
||||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
|
||||||
import google.registry.module.tools.ToolsRequestComponent.ToolsRequestComponentModule;
|
import google.registry.module.tools.ToolsRequestComponent.ToolsRequestComponentModule;
|
||||||
import google.registry.monitoring.whitebox.StackdriverModule;
|
import google.registry.monitoring.whitebox.StackdriverModule;
|
||||||
import google.registry.privileges.secretmanager.SecretManagerModule;
|
import google.registry.privileges.secretmanager.SecretManagerModule;
|
||||||
@@ -49,7 +47,6 @@ import javax.inject.Singleton;
|
|||||||
CustomLogicFactoryModule.class,
|
CustomLogicFactoryModule.class,
|
||||||
CloudTasksUtilsModule.class,
|
CloudTasksUtilsModule.class,
|
||||||
DirectoryModule.class,
|
DirectoryModule.class,
|
||||||
DummyKeyringModule.class,
|
|
||||||
DriveModule.class,
|
DriveModule.class,
|
||||||
GroupsModule.class,
|
GroupsModule.class,
|
||||||
GroupssettingsModule.class,
|
GroupssettingsModule.class,
|
||||||
@@ -57,7 +54,6 @@ import javax.inject.Singleton;
|
|||||||
KeyModule.class,
|
KeyModule.class,
|
||||||
KeyringModule.class,
|
KeyringModule.class,
|
||||||
NetHttpTransportModule.class,
|
NetHttpTransportModule.class,
|
||||||
SecretManagerKeyringModule.class,
|
|
||||||
SecretManagerModule.class,
|
SecretManagerModule.class,
|
||||||
ServerTridProviderModule.class,
|
ServerTridProviderModule.class,
|
||||||
StackdriverModule.class,
|
StackdriverModule.class,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ package google.registry.persistence;
|
|||||||
import dagger.Component;
|
import dagger.Component;
|
||||||
import google.registry.config.CredentialModule;
|
import google.registry.config.CredentialModule;
|
||||||
import google.registry.config.RegistryConfig.ConfigModule;
|
import google.registry.config.RegistryConfig.ConfigModule;
|
||||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
import google.registry.keyring.KeyringModule;
|
||||||
import google.registry.persistence.PersistenceModule.DefaultJpaTm;
|
import google.registry.persistence.PersistenceModule.DefaultJpaTm;
|
||||||
import google.registry.persistence.PersistenceModule.ReadOnlyReplicaJpaTm;
|
import google.registry.persistence.PersistenceModule.ReadOnlyReplicaJpaTm;
|
||||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||||
@@ -32,8 +32,8 @@ import javax.inject.Singleton;
|
|||||||
modules = {
|
modules = {
|
||||||
ConfigModule.class,
|
ConfigModule.class,
|
||||||
CredentialModule.class,
|
CredentialModule.class,
|
||||||
|
KeyringModule.class,
|
||||||
PersistenceModule.class,
|
PersistenceModule.class,
|
||||||
SecretManagerKeyringModule.class,
|
|
||||||
SecretManagerModule.class,
|
SecretManagerModule.class,
|
||||||
UtilsModule.class
|
UtilsModule.class
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -34,14 +34,10 @@ import dagger.BindsOptionalOf;
|
|||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
import google.registry.config.RegistryConfig.Config;
|
import google.registry.config.RegistryConfig.Config;
|
||||||
import google.registry.keyring.KeyringModule;
|
|
||||||
import google.registry.keyring.api.DummyKeyringModule;
|
|
||||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
|
||||||
import google.registry.persistence.transaction.CloudSqlCredentialSupplier;
|
import google.registry.persistence.transaction.CloudSqlCredentialSupplier;
|
||||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||||
import google.registry.persistence.transaction.JpaTransactionManagerImpl;
|
import google.registry.persistence.transaction.JpaTransactionManagerImpl;
|
||||||
import google.registry.persistence.transaction.TransactionManager;
|
import google.registry.persistence.transaction.TransactionManager;
|
||||||
import google.registry.privileges.secretmanager.SecretManagerModule;
|
|
||||||
import google.registry.privileges.secretmanager.SqlCredential;
|
import google.registry.privileges.secretmanager.SqlCredential;
|
||||||
import google.registry.privileges.secretmanager.SqlCredentialStore;
|
import google.registry.privileges.secretmanager.SqlCredentialStore;
|
||||||
import google.registry.privileges.secretmanager.SqlUser;
|
import google.registry.privileges.secretmanager.SqlUser;
|
||||||
@@ -67,14 +63,7 @@ import javax.inject.Singleton;
|
|||||||
import org.hibernate.cfg.Environment;
|
import org.hibernate.cfg.Environment;
|
||||||
|
|
||||||
/** Dagger module class for the persistence layer. */
|
/** Dagger module class for the persistence layer. */
|
||||||
// TODO(b/388835696): Use SecreteManagerKeyring in all environments and drop the `includes` below.
|
@Module
|
||||||
@Module(
|
|
||||||
includes = {
|
|
||||||
KeyringModule.class,
|
|
||||||
SecretManagerModule.class,
|
|
||||||
DummyKeyringModule.class,
|
|
||||||
SecretManagerKeyringModule.class
|
|
||||||
})
|
|
||||||
public abstract class PersistenceModule {
|
public abstract class PersistenceModule {
|
||||||
|
|
||||||
// This name must be the same as the one defined in persistence.xml.
|
// This name must be the same as the one defined in persistence.xml.
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ import google.registry.dns.writer.VoidDnsWriterModule;
|
|||||||
import google.registry.dns.writer.clouddns.CloudDnsWriterModule;
|
import google.registry.dns.writer.clouddns.CloudDnsWriterModule;
|
||||||
import google.registry.dns.writer.dnsupdate.DnsUpdateWriterModule;
|
import google.registry.dns.writer.dnsupdate.DnsUpdateWriterModule;
|
||||||
import google.registry.keyring.KeyringModule;
|
import google.registry.keyring.KeyringModule;
|
||||||
import google.registry.keyring.api.DummyKeyringModule;
|
|
||||||
import google.registry.keyring.api.KeyModule;
|
import google.registry.keyring.api.KeyModule;
|
||||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
|
||||||
import google.registry.model.ModelModule;
|
import google.registry.model.ModelModule;
|
||||||
import google.registry.persistence.PersistenceModule;
|
import google.registry.persistence.PersistenceModule;
|
||||||
import google.registry.persistence.PersistenceModule.NomulusToolJpaTm;
|
import google.registry.persistence.PersistenceModule.NomulusToolJpaTm;
|
||||||
@@ -60,7 +58,6 @@ import javax.inject.Singleton;
|
|||||||
ConfigModule.class,
|
ConfigModule.class,
|
||||||
CloudDnsWriterModule.class,
|
CloudDnsWriterModule.class,
|
||||||
CloudTasksUtilsModule.class,
|
CloudTasksUtilsModule.class,
|
||||||
DummyKeyringModule.class,
|
|
||||||
DnsUpdateWriterModule.class,
|
DnsUpdateWriterModule.class,
|
||||||
GsonModule.class,
|
GsonModule.class,
|
||||||
KeyModule.class,
|
KeyModule.class,
|
||||||
@@ -71,7 +68,6 @@ import javax.inject.Singleton;
|
|||||||
RdeModule.class,
|
RdeModule.class,
|
||||||
RegistryToolDataflowModule.class,
|
RegistryToolDataflowModule.class,
|
||||||
RequestFactoryModule.class,
|
RequestFactoryModule.class,
|
||||||
SecretManagerKeyringModule.class,
|
|
||||||
SecretManagerModule.class,
|
SecretManagerModule.class,
|
||||||
UrlConnectionServiceModule.class,
|
UrlConnectionServiceModule.class,
|
||||||
UtilsModule.class,
|
UtilsModule.class,
|
||||||
|
|||||||
@@ -1,335 +0,0 @@
|
|||||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package google.registry.keyring.api;
|
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
|
||||||
import static google.registry.testing.LogsSubject.assertAboutLogs;
|
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import com.google.common.testing.TestLogHandler;
|
|
||||||
import google.registry.util.JdkLoggerConfig;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import org.bouncycastle.bcpg.BCPGKey;
|
|
||||||
import org.bouncycastle.bcpg.PublicKeyPacket;
|
|
||||||
import org.bouncycastle.openpgp.PGPKeyPair;
|
|
||||||
import org.bouncycastle.openpgp.PGPPrivateKey;
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
/** Unit tests for {@link ComparatorKeyring}. */
|
|
||||||
class ComparatorKeyringTest {
|
|
||||||
|
|
||||||
private static final String PUBLIC_KEY_FINGERPRINT = "fingerprint";
|
|
||||||
private static final String PUBLIC_KEY_TO_STRING =
|
|
||||||
"PGPPublicKey{fingerprint=66:69:6e:67:65:72:70:72:69:6e:74:}";
|
|
||||||
private static final String PRIVATE_KEY_TO_STRING =
|
|
||||||
"PGPPrivateKey{keyId=1}";
|
|
||||||
private static final String KEY_PAIR_TO_STRING =
|
|
||||||
String.format("PGPKeyPair{%s, %s}", PUBLIC_KEY_TO_STRING, PRIVATE_KEY_TO_STRING);
|
|
||||||
|
|
||||||
private static PGPPublicKey mockPublicKey(
|
|
||||||
boolean altFingerprint,
|
|
||||||
boolean altEncoded) throws IOException {
|
|
||||||
PGPPublicKey publicKey = mock(PGPPublicKey.class);
|
|
||||||
String fingerprint = altFingerprint ? "alternate" : PUBLIC_KEY_FINGERPRINT;
|
|
||||||
String encoded = altEncoded ? "alternate" : "publicKeyEncoded";
|
|
||||||
when(publicKey.getFingerprint()).thenReturn(fingerprint.getBytes(UTF_8));
|
|
||||||
when(publicKey.getEncoded()).thenReturn(encoded.getBytes(UTF_8));
|
|
||||||
return publicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PGPPrivateKey mockPrivateKey(
|
|
||||||
boolean altId,
|
|
||||||
boolean altBcpgKeyFormat,
|
|
||||||
boolean altBcpgKeyEncoded,
|
|
||||||
boolean altPublicKeyPacketEncoded)
|
|
||||||
throws IOException {
|
|
||||||
String bcpgKeyFormat = altBcpgKeyFormat ? "alternate" : "bcpgFormat";
|
|
||||||
String bcpgKeyEncoded = altBcpgKeyEncoded ? "alternate" : "bcpgEncoded";
|
|
||||||
String publicKeyPacketEncoded = altPublicKeyPacketEncoded ? "alternate" : "packetEncoded";
|
|
||||||
|
|
||||||
BCPGKey bcpgKey = mock(BCPGKey.class);
|
|
||||||
PublicKeyPacket publicKeyPacket = mock(PublicKeyPacket.class);
|
|
||||||
when(bcpgKey.getFormat()).thenReturn(bcpgKeyFormat);
|
|
||||||
when(bcpgKey.getEncoded()).thenReturn(bcpgKeyEncoded.getBytes(UTF_8));
|
|
||||||
when(publicKeyPacket.getEncoded()).thenReturn(publicKeyPacketEncoded.getBytes(UTF_8));
|
|
||||||
return new PGPPrivateKey(altId ? 2 : 1, publicKeyPacket, bcpgKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final TestLogHandler testLogHandler = new TestLogHandler();
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void beforeEach() {
|
|
||||||
JdkLoggerConfig.getConfig(ComparatorKeyring.class).addHandler(testLogHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
void afterEach() {
|
|
||||||
JdkLoggerConfig.getConfig(ComparatorKeyring.class).removeHandler(testLogHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPublicKeyToString() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.stringify(
|
|
||||||
mockPublicKey(false, false)))
|
|
||||||
.isEqualTo(PUBLIC_KEY_TO_STRING);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPublicKeyEquals() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.compare(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPublicKey(false, false)))
|
|
||||||
.isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPublicKeyDifferFingerprint_notEqual() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.compare(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPublicKey(true, false)))
|
|
||||||
.isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPublicKeyDifferEncoded_notEqual() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.compare(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPublicKey(false, true)))
|
|
||||||
.isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPrivateKeyToString() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.stringify(
|
|
||||||
mockPrivateKey(false, false, false, false)))
|
|
||||||
.isEqualTo(PRIVATE_KEY_TO_STRING);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPrivateKeyEquals() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.compare(
|
|
||||||
mockPrivateKey(false, false, false, false),
|
|
||||||
mockPrivateKey(false, false, false, false)))
|
|
||||||
.isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPrivateKeyDifferId_notEquals() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.compare(
|
|
||||||
mockPrivateKey(false, false, false, false),
|
|
||||||
mockPrivateKey(true, false, false, false)))
|
|
||||||
.isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPrivateKeyDifferBcpgFormat_notEquals() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.compare(
|
|
||||||
mockPrivateKey(false, false, false, false),
|
|
||||||
mockPrivateKey(false, true, false, false)))
|
|
||||||
.isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPrivateKeyDifferBcpgEncoding_notEquals() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.compare(
|
|
||||||
mockPrivateKey(false, false, false, false),
|
|
||||||
mockPrivateKey(false, false, true, false)))
|
|
||||||
.isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testPrivateKeyDifferPublicKeyEncoding_notEquals() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.compare(
|
|
||||||
mockPrivateKey(false, false, false, false),
|
|
||||||
mockPrivateKey(false, false, false, true)))
|
|
||||||
.isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testKeyPairToString() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.stringify(
|
|
||||||
new PGPKeyPair(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPrivateKey(false, false, false, false))))
|
|
||||||
.isEqualTo(KEY_PAIR_TO_STRING);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testKeyPairEquals() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.compare(
|
|
||||||
new PGPKeyPair(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPrivateKey(false, false, false, false)),
|
|
||||||
new PGPKeyPair(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPrivateKey(false, false, false, false))))
|
|
||||||
.isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testKeyPairDifferPublicKey_notEqual() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.compare(
|
|
||||||
new PGPKeyPair(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPrivateKey(false, false, false, false)),
|
|
||||||
new PGPKeyPair(
|
|
||||||
mockPublicKey(true, false),
|
|
||||||
mockPrivateKey(false, false, false, false))))
|
|
||||||
.isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testKeyPairDifferPrivateKey_notEqual() throws Exception {
|
|
||||||
assertThat(
|
|
||||||
ComparatorKeyring.compare(
|
|
||||||
new PGPKeyPair(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPrivateKey(false, false, false, false)),
|
|
||||||
new PGPKeyPair(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPrivateKey(true, false, false, false))))
|
|
||||||
.isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't need to check every single method in the generated instance to see that it behaves
|
|
||||||
// correctly. This should have been tested in ComparatorGenerator.
|
|
||||||
//
|
|
||||||
// We will fully test a single method just to make sure everything is "connected" correctly.
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testRdeSigningKey_actualThrows() throws Exception {
|
|
||||||
Keyring actualKeyring = mock(Keyring.class);
|
|
||||||
Keyring secondKeyring = mock(Keyring.class);
|
|
||||||
PGPKeyPair keyPair =
|
|
||||||
new PGPKeyPair(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPrivateKey(false, false, false, false));
|
|
||||||
when(actualKeyring.getRdeSigningKey()).thenThrow(new KeyringException("message"));
|
|
||||||
when(secondKeyring.getRdeSigningKey()).thenReturn(keyPair);
|
|
||||||
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
|
|
||||||
|
|
||||||
assertThrows(KeyringException.class, comparatorKeyring::getRdeSigningKey);
|
|
||||||
|
|
||||||
assertAboutLogs()
|
|
||||||
.that(testLogHandler)
|
|
||||||
.hasLogAtLevelWithMessage(
|
|
||||||
Level.SEVERE, ".getRdeSigningKey: Only actual implementation threw exception");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testRdeSigningKey_secondThrows() throws Exception {
|
|
||||||
Keyring actualKeyring = mock(Keyring.class);
|
|
||||||
Keyring secondKeyring = mock(Keyring.class);
|
|
||||||
PGPKeyPair keyPair =
|
|
||||||
new PGPKeyPair(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPrivateKey(false, false, false, false));
|
|
||||||
when(actualKeyring.getRdeSigningKey()).thenReturn(keyPair);
|
|
||||||
when(secondKeyring.getRdeSigningKey()).thenThrow(new KeyringException("message"));
|
|
||||||
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
|
|
||||||
|
|
||||||
assertThat(comparatorKeyring.getRdeSigningKey()).isSameInstanceAs(keyPair);
|
|
||||||
|
|
||||||
assertAboutLogs()
|
|
||||||
.that(testLogHandler)
|
|
||||||
.hasLogAtLevelWithMessage(
|
|
||||||
Level.SEVERE, ".getRdeSigningKey: Only second implementation threw exception");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testRdeSigningKey_bothThrow() {
|
|
||||||
Keyring actualKeyring = mock(Keyring.class);
|
|
||||||
Keyring secondKeyring = mock(Keyring.class);
|
|
||||||
when(actualKeyring.getRdeSigningKey()).thenThrow(new KeyringException("message"));
|
|
||||||
when(secondKeyring.getRdeSigningKey()).thenThrow(new KeyringException("message"));
|
|
||||||
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
|
|
||||||
|
|
||||||
assertThrows(KeyringException.class, comparatorKeyring::getRdeSigningKey);
|
|
||||||
|
|
||||||
assertAboutLogs().that(testLogHandler).hasNoLogsAtLevel(Level.SEVERE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testRdeSigningKey_same() throws Exception {
|
|
||||||
Keyring actualKeyring = mock(Keyring.class);
|
|
||||||
Keyring secondKeyring = mock(Keyring.class);
|
|
||||||
PGPKeyPair keyPair =
|
|
||||||
new PGPKeyPair(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPrivateKey(false, false, false, false));
|
|
||||||
PGPKeyPair keyPairCopy =
|
|
||||||
new PGPKeyPair(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPrivateKey(false, false, false, false));
|
|
||||||
when(actualKeyring.getRdeSigningKey()).thenReturn(keyPair);
|
|
||||||
when(secondKeyring.getRdeSigningKey()).thenReturn(keyPairCopy);
|
|
||||||
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
|
|
||||||
|
|
||||||
assertThat(comparatorKeyring.getRdeSigningKey()).isSameInstanceAs(keyPair);
|
|
||||||
|
|
||||||
assertAboutLogs().that(testLogHandler).hasNoLogsAtLevel(Level.SEVERE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testRdeSigningKey_different() throws Exception {
|
|
||||||
Keyring actualKeyring = mock(Keyring.class);
|
|
||||||
Keyring secondKeyring = mock(Keyring.class);
|
|
||||||
PGPKeyPair keyPair =
|
|
||||||
new PGPKeyPair(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPrivateKey(false, false, false, false));
|
|
||||||
PGPKeyPair keyPairDifferent =
|
|
||||||
new PGPKeyPair(
|
|
||||||
mockPublicKey(false, false),
|
|
||||||
mockPrivateKey(true, false, false, false));
|
|
||||||
when(actualKeyring.getRdeSigningKey()).thenReturn(keyPair);
|
|
||||||
when(secondKeyring.getRdeSigningKey()).thenReturn(keyPairDifferent);
|
|
||||||
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
|
|
||||||
|
|
||||||
assertThat(comparatorKeyring.getRdeSigningKey()).isSameInstanceAs(keyPair);
|
|
||||||
|
|
||||||
String alternateKeyPairString = String.format(
|
|
||||||
"PGPKeyPair{%s, %s}", PUBLIC_KEY_TO_STRING, "PGPPrivateKey{keyId=2}");
|
|
||||||
|
|
||||||
assertAboutLogs()
|
|
||||||
.that(testLogHandler)
|
|
||||||
.hasLogAtLevelWithMessage(
|
|
||||||
Level.SEVERE,
|
|
||||||
String.format(
|
|
||||||
".getRdeSigningKey: Got different results! '%s' vs '%s'",
|
|
||||||
KEY_PAIR_TO_STRING,
|
|
||||||
alternateKeyPairString));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,7 +20,6 @@ import dagger.Component;
|
|||||||
import google.registry.config.CredentialModule;
|
import google.registry.config.CredentialModule;
|
||||||
import google.registry.config.RegistryConfig.Config;
|
import google.registry.config.RegistryConfig.Config;
|
||||||
import google.registry.config.RegistryConfig.ConfigModule;
|
import google.registry.config.RegistryConfig.ConfigModule;
|
||||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
|
||||||
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
|
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
|
||||||
import google.registry.privileges.secretmanager.SecretManagerModule;
|
import google.registry.privileges.secretmanager.SecretManagerModule;
|
||||||
import google.registry.util.UtilsModule;
|
import google.registry.util.UtilsModule;
|
||||||
@@ -84,7 +83,6 @@ class PersistenceModuleTest {
|
|||||||
ConfigModule.class,
|
ConfigModule.class,
|
||||||
CredentialModule.class,
|
CredentialModule.class,
|
||||||
PersistenceModule.class,
|
PersistenceModule.class,
|
||||||
SecretManagerKeyringModule.class,
|
|
||||||
SecretManagerModule.class,
|
SecretManagerModule.class,
|
||||||
UtilsModule.class
|
UtilsModule.class
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ updated by running `nomulus` commands without having to deploy a new version.
|
|||||||
Here's a checklist of things that need to be configured upon initial
|
Here's a checklist of things that need to be configured upon initial
|
||||||
installation of the project:
|
installation of the project:
|
||||||
|
|
||||||
* Create Google Cloud Storage buckets (see the [Architecture
|
* Create Google Cloud Storage buckets (see the
|
||||||
documentation](./architecture.md) for more information).
|
[Architecture documentation](./architecture.md) for more information).
|
||||||
* Modify configuration files ("nomulus-config-*.yaml") for all environments
|
* Modify configuration files ("nomulus-config-*.yaml") for all environments
|
||||||
you wish to deploy.
|
you wish to deploy.
|
||||||
|
|
||||||
@@ -35,13 +35,13 @@ App Engine configuration isn't covered in depth in this document as it is
|
|||||||
thoroughly documented in the [App Engine configuration docs][app-engine-config].
|
thoroughly documented in the [App Engine configuration docs][app-engine-config].
|
||||||
The main files of note that come pre-configured in Nomulus are:
|
The main files of note that come pre-configured in Nomulus are:
|
||||||
|
|
||||||
* `cron.xml` -- Configuration of cronjobs
|
* `cron.xml` -- Configuration of cronjobs
|
||||||
* `web.xml` -- Configuration of URL paths on the webserver
|
* `web.xml` -- Configuration of URL paths on the webserver
|
||||||
* `appengine-web.xml` -- Overall App Engine settings including number and type
|
* `appengine-web.xml` -- Overall App Engine settings including number and type
|
||||||
of instances
|
of instances
|
||||||
* `cloud-scheduler-tasks.xml` -- Configuration of Cloud Scheduler Tasks
|
* `cloud-scheduler-tasks.xml` -- Configuration of Cloud Scheduler Tasks
|
||||||
* * `cloud-tasks-queue.xml` -- Configuration of Cloud Tasks Queue
|
* * `cloud-tasks-queue.xml` -- Configuration of Cloud Tasks Queue
|
||||||
* `application.xml` -- Configuration of the application name and its services
|
* `application.xml` -- Configuration of the application name and its services
|
||||||
|
|
||||||
Cron, web, and queue are covered in more detail in the "App Engine architecture"
|
Cron, web, and queue are covered in more detail in the "App Engine architecture"
|
||||||
doc, and the rest are covered in the general App Engine documentation.
|
doc, and the rest are covered in the general App Engine documentation.
|
||||||
@@ -53,10 +53,9 @@ likely you'll need to add cronjobs, URL paths, and task queues, and thus edit
|
|||||||
those associated XML files.
|
those associated XML files.
|
||||||
|
|
||||||
The existing codebase is configured for running a full-scale registry with
|
The existing codebase is configured for running a full-scale registry with
|
||||||
multiple TLDs. In order to deploy to App Engine, you will either need to
|
multiple TLDs. In order to deploy to App Engine, you will either need to
|
||||||
[increase your
|
[increase your quota](https://cloud.google.com/compute/quotas#requesting_additional_quota)
|
||||||
quota](https://cloud.google.com/compute/quotas#requesting_additional_quota) to
|
to allow for at least 100 running instances or reduce `max-instances` in the
|
||||||
allow for at least 100 running instances or reduce `max-instances` in the
|
|
||||||
backend `appengine-web.xml` files to 25 or less.
|
backend `appengine-web.xml` files to 25 or less.
|
||||||
|
|
||||||
## Global configuration
|
## Global configuration
|
||||||
@@ -93,9 +92,9 @@ need to specify more settings.
|
|||||||
From a code perspective, all configuration settings ultimately come through the
|
From a code perspective, all configuration settings ultimately come through the
|
||||||
[`RegistryConfig`][registry-config] class. This includes a Dagger module called
|
[`RegistryConfig`][registry-config] class. This includes a Dagger module called
|
||||||
`ConfigModule` that provides injectable configuration options. While most
|
`ConfigModule` that provides injectable configuration options. While most
|
||||||
configuration options can be changed from within the yaml config file,
|
configuration options can be changed from within the yaml config file, certain
|
||||||
certain derived options may still need to be overriden by changing the code in
|
derived options may still need to be overriden by changing the code in this
|
||||||
this module.
|
module.
|
||||||
|
|
||||||
## OAuth 2 client id configuration
|
## OAuth 2 client id configuration
|
||||||
|
|
||||||
@@ -119,10 +118,9 @@ There are three steps to configuration.
|
|||||||
["Credentials" page](https://console.developers.google.com/apis/credentials)
|
["Credentials" page](https://console.developers.google.com/apis/credentials)
|
||||||
in the Developer's Console. Click "Create credentials" and select "OAuth
|
in the Developer's Console. Click "Create credentials" and select "OAuth
|
||||||
client ID" from the dropdown. In the create credentials window, select an
|
client ID" from the dropdown. In the create credentials window, select an
|
||||||
application type of "Desktop app". After creating the client id,
|
application type of "Desktop app". After creating the client id, copy the
|
||||||
copy the client id and client secret which are displayed in the popup
|
client id and client secret which are displayed in the popup window. You may
|
||||||
window. You may also obtain this information by downloading the json file
|
also obtain this information by downloading the json file for the client id.
|
||||||
for the client id.
|
|
||||||
|
|
||||||
* **Copy the client secret information to the config file:** The *client
|
* **Copy the client secret information to the config file:** The *client
|
||||||
secret file* contains both the client ID and the client secret. Copy the
|
secret file* contains both the client ID and the client secret. Copy the
|
||||||
@@ -150,29 +148,24 @@ Some configuration values, such as PGP private keys, are so sensitive that they
|
|||||||
should not be written in code as per the configuration methods above, as that
|
should not be written in code as per the configuration methods above, as that
|
||||||
would pose too high a risk of them accidentally being leaked, e.g. in a source
|
would pose too high a risk of them accidentally being leaked, e.g. in a source
|
||||||
control mishap. We use a secret store to persist these values in a secure
|
control mishap. We use a secret store to persist these values in a secure
|
||||||
manner, and abstract access to them using the `Keyring` interface.
|
manner, which is backed by the GCP Secret Manager.
|
||||||
|
|
||||||
The `Keyring` interface contains methods for all sensitive configuration values,
|
The `Keyring` interface contains methods for all sensitive configuration values,
|
||||||
which are primarily credentials used to access various ICANN and ICANN-
|
which are primarily credentials used to access various ICANN and ICANN-
|
||||||
affiliated services (such as RDE). These values are only needed for real
|
affiliated services (such as RDE). These values are only needed for real
|
||||||
production registries and PDT environments. If you are just playing around with
|
production registries and PDT environments. If you are just playing around with
|
||||||
the platform at first, it is OK to put off defining these values until
|
the platform at first, it is OK to put off defining these values until
|
||||||
necessary. To that end, a `DummyKeyringModule` is included that simply provides
|
necessary. This allows the codebase to start and run, but of course any actions
|
||||||
an `InMemoryKeyring` populated with dummy values for all secret keys. This
|
that attempt to connect to external services will fail because if the relevant
|
||||||
allows the codebase to compile and run, but of course any actions that attempt
|
key is not found in the Secret Manager.
|
||||||
to connect to external services will fail because none of the keys are real.
|
|
||||||
|
|
||||||
To configure a production registry system, you will need to either use the
|
To configure a production registry system, you will need to add the required
|
||||||
SecretManagerKeyring or write your own replacement module using
|
keys to the Secret Manager. To do so, you can use the Nomulus tool's
|
||||||
`DummyKeyringModule` for guidance. Such a module should provide either an
|
`update_keyring_secret` command. First, run `nomulus -e ${ENV}
|
||||||
instance of `InMemoryKeyring` or your own custom implementation of `Keyring`.
|
update_keyring_secret` to get the list of all key names (whose meanings should
|
||||||
|
be obvious); then, for each key to be added or updated, put the data in a file
|
||||||
In either case, configure the `keyring` section of the config file with the
|
and run `nomulus -e ${ENV} update_keyring_secret --input ${FILE} --keyname
|
||||||
appropriate parameters. Use an `activeKeyring` of "CSM" with a project id for
|
${KEY_NAME}`.
|
||||||
SecretManager to configure accordingly, for example:
|
|
||||||
|
|
||||||
keyring:
|
|
||||||
activeKeyring: CSM
|
|
||||||
|
|
||||||
## Per-TLD configuration
|
## Per-TLD configuration
|
||||||
|
|
||||||
@@ -181,8 +174,8 @@ configuration. They contain any kind of configuration that is specific to a TLD,
|
|||||||
such as the create/renew price of a domain name, the pricing engine
|
such as the create/renew price of a domain name, the pricing engine
|
||||||
implementation, the DNS writer implementation, whether escrow exports are
|
implementation, the DNS writer implementation, whether escrow exports are
|
||||||
enabled, the default currency, the reserved label lists, and more. The `nomulus
|
enabled, the default currency, the reserved label lists, and more. The `nomulus
|
||||||
update_tld` command is used to set all of these options. See the [admin tool
|
update_tld` command is used to set all of these options. See the
|
||||||
documentation](./admin-tool.md) for more information, as well as the
|
[admin tool documentation](./admin-tool.md) for more information, as well as the
|
||||||
command-line help for the `update_tld` command. Unlike global configuration
|
command-line help for the `update_tld` command. Unlike global configuration
|
||||||
above, per-TLD configuration options are stored as data in the running system,
|
above, per-TLD configuration options are stored as data in the running system,
|
||||||
and thus do not require code pushes to update.
|
and thus do not require code pushes to update.
|
||||||
@@ -193,121 +186,150 @@ and thus do not require code pushes to update.
|
|||||||
|
|
||||||
## Cloud SQL Configuration
|
## Cloud SQL Configuration
|
||||||
|
|
||||||
Nomulus requires access to Cloud SQL and thus the necessary configuration
|
Nomulus requires access to Cloud SQL and thus the necessary configuration must
|
||||||
must be applied.
|
be applied.
|
||||||
|
|
||||||
### Create Postgres Cloud SQL Instance
|
### Create Postgres Cloud SQL Instance
|
||||||
|
|
||||||
You can create a cloud SQL instance using the gcloud command:
|
You can create a cloud SQL instance using the gcloud command:
|
||||||
|
|
||||||
$ gcloud sql instances create nomulus --database-version=POSTGRES_11 \
|
```
|
||||||
--cpu=1 --memory=4G
|
$ gcloud sql instances create nomulus --database-version=POSTGRES_17 \
|
||||||
|
--cpu=1 --memory=4G
|
||||||
|
```
|
||||||
|
|
||||||
Note that for a production instance, you will likely want to be far more
|
Note that for a production instance, you will likely want to be far more
|
||||||
generous with both CPU and memory resources.
|
generous with both CPU and memory resources.
|
||||||
|
|
||||||
Now get the connection name for the new database:
|
|
||||||
|
|
||||||
$ gcloud sql instances describe nomulus | grep connectionName
|
|
||||||
connectionName: your-project:us-central1:nomulus
|
|
||||||
|
|
||||||
Copy the connection name into your configuration (see below).
|
|
||||||
|
|
||||||
Now set the password for the default user:
|
Now set the password for the default user:
|
||||||
|
|
||||||
$ gcloud sql users set-password postgres \
|
```
|
||||||
--instance=nomulus --project=$PROJECT_ID \
|
$ gcloud sql users set-password postgres \
|
||||||
--prompt-for-password
|
--instance=nomulus --project=$PROJECT_ID \
|
||||||
|
--prompt-for-password
|
||||||
|
```
|
||||||
|
|
||||||
Store this password somewhere secure.
|
Store this password somewhere secure.
|
||||||
|
|
||||||
Now create database users for the tool and for the backend. First, you'll
|
Now create database users for the tool and for the backend. First, you'll need
|
||||||
need to create a password. This can simply be a sequence of random
|
to create a password. This can simply be a sequence of random characters. Write
|
||||||
characters. Write it to the file `/tmp/server.pass` (we'll use a single
|
it to the file `/tmp/server.pass` (we'll use a single password for the two user
|
||||||
password for the two user accounts here, you are encouraged to use different
|
accounts here, you are encouraged to use different passwords for your production
|
||||||
passwords for your production systems). Make sure that this file does not
|
systems). Make sure that this file does not contain a newline after the
|
||||||
contain a newline after the password. Now create the two user accounts:
|
password. Now create the two user accounts:
|
||||||
|
|
||||||
$ gcloud sql users create nomulus --instance=nomulus \
|
```
|
||||||
--project=$PROJECT_ID "--password=`cat /tmp/server.pass`"
|
$ gcloud sql users create nomulus --instance=nomulus \
|
||||||
$ gcloud sql users create tool --instance=nomulus \
|
--project=$PROJECT_ID "--password=`cat /tmp/server.pass`"
|
||||||
--project=$PROJECT_ID "--password=`cat /tmp/server.pass`"
|
$ gcloud sql users create tool --instance=nomulus \
|
||||||
|
--project=$PROJECT_ID "--password=`cat /tmp/server.pass`"
|
||||||
|
```
|
||||||
|
|
||||||
Now enable access to the Cloud SQL admin APIs:
|
Now enable access to the Cloud SQL admin APIs:
|
||||||
|
|
||||||
$ gcloud services enable sqladmin.googleapis.com \
|
```
|
||||||
--project=$PROJECT_ID
|
$ gcloud services enable sqladmin.googleapis.com \
|
||||||
|
--project=$PROJECT_ID
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, add the database instance names to the keyring. First, get the
|
||||||
|
connection name for the new database:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gcloud sql instances describe nomulus | grep connectionName
|
||||||
|
connectionName: your-project:us-central1:nomulus
|
||||||
|
```
|
||||||
|
|
||||||
|
Use the `update_keyring_secret` command to update the `SQL_PRIMARY_CONN_NAME`
|
||||||
|
key with the connection name. If you have created a read-replica, update the
|
||||||
|
`SQL_REPLICA_CONN_NAME` key with the replica's connection time.
|
||||||
|
|
||||||
### Installing the Schema
|
### Installing the Schema
|
||||||
|
|
||||||
Google's Nomulus team makes use of Spinnaker-based continuous integration to
|
Google's Nomulus team makes use of Spinnaker-based continuous integration to
|
||||||
perform weekly pushes of both the Nomulus software and the SQL database
|
perform weekly pushes of both the Nomulus software and the SQL database schema.
|
||||||
schema. Organizations wishing to use the Nomulus software will likely want to
|
Organizations wishing to use the Nomulus software will likely want to do
|
||||||
do something similar. However, for purposes of this exercise we will push the
|
something similar. However, for purposes of this exercise we will push the
|
||||||
schema from the build system.
|
schema from the build system.
|
||||||
|
|
||||||
First, download the [Cloud SQL
|
First, download the
|
||||||
Proxy](https://cloud.google.com/sql/docs/mysql/sql-proxy). This will allow
|
[Cloud SQL Proxy](https://cloud.google.com/sql/docs/mysql/sql-proxy). This will
|
||||||
you to connect to your database from a local workstation without a lot of
|
allow you to connect to your database from a local workstation without a lot of
|
||||||
additional configuration.
|
additional configuration.
|
||||||
|
|
||||||
Create a service account for use with the proxy:
|
Create a service account for use with the proxy:
|
||||||
|
|
||||||
$ gcloud iam service-accounts create sql-proxy \
|
```
|
||||||
--project=$PROJECT_ID \
|
$ gcloud iam service-accounts create sql-proxy \
|
||||||
--description="Service account for use with Cloud SQL Proxy" \
|
--project=$PROJECT_ID \
|
||||||
--display-name="Cloud SQL Proxy"
|
--description="Service account for use with Cloud SQL Proxy" \
|
||||||
|
--display-name="Cloud SQL Proxy"
|
||||||
|
```
|
||||||
|
|
||||||
Give the service account admin permissions:
|
Give the service account admin permissions:
|
||||||
|
|
||||||
$ gcloud projects add-iam-policy-binding $PROJECT_ID \
|
```
|
||||||
--member=serviceAccount:sql-proxy@$PROJECT_ID.iam.gserviceaccount.com \
|
$ gcloud projects add-iam-policy-binding $PROJECT_ID \
|
||||||
--role=roles/cloudsql.admin
|
--member=serviceAccount:sql-proxy@$PROJECT_ID.iam.gserviceaccount.com \
|
||||||
|
--role=roles/cloudsql.admin
|
||||||
|
```
|
||||||
|
|
||||||
Create a JSON key for the service account:
|
Create a JSON key for the service account:
|
||||||
|
|
||||||
$ gcloud iam service-accounts keys create sql-admin.json \
|
```
|
||||||
--project=$PROJECT_ID \
|
$ gcloud iam service-accounts keys create sql-admin.json \
|
||||||
--iam-account=sql-proxy@$PROJECT_ID.iam.gserviceaccount.com
|
--project=$PROJECT_ID \
|
||||||
|
--iam-account=sql-proxy@$PROJECT_ID.iam.gserviceaccount.com
|
||||||
|
```
|
||||||
|
|
||||||
Now start the proxy:
|
Now start the proxy:
|
||||||
|
|
||||||
$ PORT=3306 # Use a different value for this if you like.
|
```
|
||||||
$ ./cloud_sql_proxy -credential_file=sql-admin.json \
|
$ PORT=3306 # Use a different value for this if you like.
|
||||||
-instances=$PROJECT_ID:nomulus=tcp:$PORT
|
$ ./cloud_sql_proxy -credential_file=sql-admin.json \
|
||||||
2020/07/01 12:11:20 current FDs rlimit set to 32768, wanted limit is 8500. Nothing to do here.
|
-instances=$PROJECT_ID:nomulus=tcp:$PORT
|
||||||
2020/07/01 12:11:20 using credential file for authentication; email=sql-proxy@pproject-id.iam.gserviceaccount.com
|
2020/07/01 12:11:20 current FDs rlimit set to 32768, wanted limit is 8500. Nothing to do here.
|
||||||
2020/07/01 12:11:20 Listening on 127.0.0.1:3306 for project-id:nomulus
|
2020/07/01 12:11:20 using credential file for authentication; email=sql-proxy@pproject-id.iam.gserviceaccount.com
|
||||||
2020/07/01 12:11:20 Ready for new connections
|
2020/07/01 12:11:20 Listening on 127.0.0.1:3306 for project-id:nomulus
|
||||||
|
2020/07/01 12:11:20 Ready for new connections
|
||||||
|
```
|
||||||
|
|
||||||
Finally, upload the new database schema:
|
Finally, upload the new database schema:
|
||||||
|
|
||||||
$ ./nom_build :db:flywayMigrate --dbServer=localhost:$PORT \
|
```
|
||||||
--dbName=postgres --dbUser=nomulus --dbPassword=`cat /tmp/server.pass`
|
$ ./nom_build :db:flywayMigrate --dbServer=localhost:$PORT \
|
||||||
|
--dbName=postgres --dbUser=nomulus --dbPassword=`cat /tmp/server.pass`
|
||||||
|
```
|
||||||
|
|
||||||
Now you'll need to give the "tool" user access to all tables. You can do this
|
Now you'll need to give the "tool" user access to all tables. You can do this
|
||||||
either with a locally installed version of PostgreSQL or from the Cloud Shell.
|
either with a locally installed version of PostgreSQL or from the Cloud Shell.
|
||||||
From local postgres, first, with your proxy is still running, connect using
|
From local postgres, first, with your proxy is still running, connect using
|
||||||
psql.
|
psql.
|
||||||
|
|
||||||
$ psql -h localhost -p 3306 postgres nomulus ~/w/nom.admin-docs
|
```
|
||||||
Password for user nomulus: <enter the password from /tmp/server.pass>
|
$ psql -h localhost -p 3306 postgres nomulus ~/w/nom.admin-docs
|
||||||
psql (12.2 (Debian 12.2-1+build2), server 11.6)
|
Password for user nomulus: <enter the password from /tmp/server.pass>
|
||||||
Type "help" for help.
|
psql (12.2 (Debian 12.2-1+build2), server 11.6)
|
||||||
|
Type "help" for help.
|
||||||
|
|
||||||
postgres=>
|
postgres=>
|
||||||
|
```
|
||||||
|
|
||||||
Enter the following command at the postgres prompt:
|
Enter the following command at the postgres prompt:
|
||||||
|
|
||||||
GRANT SELECT, INSERT, UPDATE, DELETE
|
```
|
||||||
ON ALL TABLES IN SCHEMA public
|
GRANT SELECT, INSERT, UPDATE, DELETE
|
||||||
TO tool;
|
ON ALL TABLES IN SCHEMA public
|
||||||
|
TO tool;
|
||||||
|
```
|
||||||
|
|
||||||
From the [Google Cloud Console](https://console.developers.google.com), click
|
From the [Google Cloud Console](https://console.developers.google.com), click
|
||||||
the cloud shell icon in the toolbar (the ">_" icon). You should be able to
|
the cloud shell icon in the toolbar (the ">_" icon). You should be able to
|
||||||
connect to your database with gcloud:
|
connect to your database with gcloud:
|
||||||
|
|
||||||
$ gcloud sql connect nomulus --user=nomulus
|
```
|
||||||
|
$ gcloud sql connect nomulus --user=nomulus
|
||||||
|
```
|
||||||
|
|
||||||
From this, you should have a postgres prompt and be able to enter the "GRANT"
|
From this, you should have a postgres prompt and be able to enter the "GRANT"
|
||||||
command specified above.
|
command specified above.
|
||||||
@@ -319,40 +341,31 @@ You'll need to enable the SecretManager API in your project.
|
|||||||
#### Install Cloud SQL Passwords in Nomulus Server
|
#### Install Cloud SQL Passwords in Nomulus Server
|
||||||
|
|
||||||
Use the update_keyring_secret command to upload the Cloud SQL passwords to the
|
Use the update_keyring_secret command to upload the Cloud SQL passwords to the
|
||||||
Nomulus server. We'll use the password same set of passwords we specified
|
Nomulus server. We'll use the password same set of passwords we specified above
|
||||||
above when creating database user accounts. These should currently be stored
|
when creating database user accounts. These should currently be stored in
|
||||||
in `/tmp/server.pass`.
|
`/tmp/server.pass`.
|
||||||
|
|
||||||
Paste the password for the Registry server user to a file, say
|
Paste the password for the Registry server user to a file, say /tmp/server.pass.
|
||||||
/tmp/server.pass. Make sure to avoid any trailing '\n' inserted by the editor.
|
Make sure to avoid any trailing '\n' inserted by the editor.
|
||||||
|
|
||||||
$ set ENV=alpha
|
```
|
||||||
$ nomulus -e $ENV update_keyring_secret --keyname CLOUD_SQL_PASSWORD \
|
$ set ENV=alpha
|
||||||
--input /tmp/server.pass
|
$ nomulus -e $ENV update_keyring_secret --keyname CLOUD_SQL_PASSWORD \
|
||||||
|
--input /tmp/server.pass
|
||||||
|
```
|
||||||
|
|
||||||
Repeat the steps for the tools sql password:
|
Repeat the steps for the tools sql password:
|
||||||
|
|
||||||
$ nomulus -e $ENV update_keyring_secret --keyname TOOLS_CLOUD_SQL_PASSWORD \
|
```
|
||||||
--input /tmp/tools.pass
|
$ nomulus -e $ENV update_keyring_secret --keyname TOOLS_CLOUD_SQL_PASSWORD \
|
||||||
|
--input /tmp/tools.pass
|
||||||
|
```
|
||||||
|
|
||||||
Use get_keyring_secret command to verify the data you put in:
|
Use get_keyring_secret command to verify the data you put in:
|
||||||
|
|
||||||
$ nomulus -e alpha -e alpha get_keyring_secret --keyname CLOUD_SQL_PASSWORD
|
```
|
||||||
[your password]
|
$ nomulus -e alpha -e alpha get_keyring_secret --keyname CLOUD_SQL_PASSWORD
|
||||||
$ nomulus -e alpha -e alpha get_keyring_secret --keyname CLOUD_SQL_PASSWORD
|
[your password]
|
||||||
[your password]
|
$ nomulus -e alpha -e alpha get_keyring_secret --keyname CLOUD_SQL_PASSWORD
|
||||||
|
[your password]
|
||||||
#### The Relevant Parts of the Configuration File
|
```
|
||||||
|
|
||||||
cloudSql:
|
|
||||||
jdbcUrl: jdbc:postgresql://google/postgres
|
|
||||||
username: nomulus
|
|
||||||
instanceConnectionName: THE_NAME_SHOWN_ON_THE_DB_INFO_PAGE
|
|
||||||
|
|
||||||
keyring:
|
|
||||||
activeKeyring: CSM
|
|
||||||
|
|
||||||
registryTool:
|
|
||||||
clientId: TOOLS_OAUTH_CLIENT_ID
|
|
||||||
clientSecret: TOOLS_OAUTH_SECRET
|
|
||||||
username: tool
|
|
||||||
|
|||||||
Reference in New Issue
Block a user