Skip to content

Commit

Permalink
Correctly handle generated secrets
Browse files Browse the repository at this point in the history
Secrets were re-generated on each control loop.
  • Loading branch information
Stefan Bethke committed Mar 21, 2022
1 parent 959ed00 commit ec44967
Show file tree
Hide file tree
Showing 14 changed files with 246 additions and 229 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -374,12 +374,6 @@ public long getUserId() {

@Override
public Optional<Boolean> isReady() {
if (getCmcc().getStatus().getMilestone() == null) {
log.debug("foo");
}
if (getComponentSpec().getMilestone() == null) {
log.debug("foo");
}
if (getCmcc().getStatus().getMilestone().compareTo(getComponentSpec().getMilestone()) < 0)
return Optional.empty();
return Optional.of(getTargetState().isStatefulSetReady(getTargetState().getResourceNameFor(this)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

import com.tsystemsmms.cmcc.cmccoperator.crds.ClientSecretRef;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.CustomResourceConfigError;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.DefaultClientSecret;
import com.tsystemsmms.cmcc.cmccoperator.utils.EnvVarSet;

import java.util.List;
Expand Down Expand Up @@ -50,16 +49,15 @@ default ClientSecretRef getJdbcClientSecretRef(String schemaName) {
if (!getTargetState().getCmcc().getSpec().getWith().getDatabases()) {
throw new CustomResourceConfigError("No MySQL client secret reference found for " + schemaName + ", and with.databases is false");
}
return getTargetState().getClientSecretRef(JDBC_CLIENT_SECRET_REF_KIND, schemaName, password ->
new DefaultClientSecret(ClientSecretRef.defaultClientSecretRef(secretName),
getTargetState().loadOrBuildSecret(secretName, Map.of(
return getTargetState().getClientSecretRef(JDBC_CLIENT_SECRET_REF_KIND, schemaName,
(clientSecret, password) -> getTargetState().loadOrBuildSecret(clientSecret, Map.of(
ClientSecretRef.DEFAULT_DRIVER_KEY, "com.mysql.cj.jdbc.Driver",
ClientSecretRef.DEFAULT_HOSTNAME_KEY, serviceName,
ClientSecretRef.DEFAULT_PASSWORD_KEY, password,
ClientSecretRef.DEFAULT_SCHEMA_KEY, schemaName,
ClientSecretRef.DEFAULT_URL_KEY, "jdbc:mysql://" + serviceName + ":3306/" + schemaName,
ClientSecretRef.DEFAULT_USERNAME_KEY, schemaName
))
)
)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

import com.tsystemsmms.cmcc.cmccoperator.crds.ClientSecretRef;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.CustomResourceConfigError;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.DefaultClientSecret;
import com.tsystemsmms.cmcc.cmccoperator.utils.EnvVarSet;

import java.util.List;
Expand Down Expand Up @@ -47,15 +46,13 @@ default ClientSecretRef getMongoDBClientSecretRef(String schemaName) {
if (!getTargetState().getCmcc().getSpec().getWith().getDatabases()) {
throw new CustomResourceConfigError("No MongoDB client secret reference found for " + schemaName + ", and with.databases is false");
}
return getTargetState().getClientSecretRef(MONGODB_CLIENT_SECRET_REF_KIND, schemaName, password ->
new DefaultClientSecret(ClientSecretRef.defaultClientSecretRef(secretName),
getTargetState().loadOrBuildSecret(secretName, Map.of(
ClientSecretRef.DEFAULT_PASSWORD_KEY, password,
ClientSecretRef.DEFAULT_SCHEMA_KEY, schemaName,
ClientSecretRef.DEFAULT_URL_KEY, "mongodb://" + schemaName + ":" + password + "@" + serviceName + ":27017/" + schemaName,
ClientSecretRef.DEFAULT_USERNAME_KEY, schemaName
))
)
return getTargetState().getClientSecretRef(MONGODB_CLIENT_SECRET_REF_KIND, schemaName,
(clientSecret, password) -> getTargetState().loadOrBuildSecret(clientSecret, Map.of(
ClientSecretRef.DEFAULT_PASSWORD_KEY, password,
ClientSecretRef.DEFAULT_SCHEMA_KEY, schemaName,
ClientSecretRef.DEFAULT_URL_KEY, "mongodb://" + schemaName + ":" + password + "@" + serviceName + ":27017/" + schemaName,
ClientSecretRef.DEFAULT_USERNAME_KEY, schemaName
))
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@

import com.tsystemsmms.cmcc.cmccoperator.crds.ClientSecretRef;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.CustomResourceConfigError;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.DefaultClientSecret;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.TargetState;
import com.tsystemsmms.cmcc.cmccoperator.utils.EnvVarSet;
import io.fabric8.kubernetes.api.model.ObjectMeta;

import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -68,14 +65,12 @@ default ClientSecretRef getUapiClientSecretRef(String schemaName) {
if (!getTargetState().getCmcc().getSpec().getWith().getDatabases()) {
throw new CustomResourceConfigError("No UAPI client secret reference found for " + schemaName + ", and with.databases is false");
}
return getTargetState().getClientSecretRef(UAPI_CLIENT_SECRET_REF_KIND, schemaName, password ->
new DefaultClientSecret(ClientSecretRef.defaultClientSecretRef(secretName),
getTargetState().loadOrBuildSecret(secretName, Map.of(
ClientSecretRef.DEFAULT_PASSWORD_KEY, password,
ClientSecretRef.DEFAULT_SCHEMA_KEY, schemaName,
ClientSecretRef.DEFAULT_USERNAME_KEY, schemaName
))
)
return getTargetState().getClientSecretRef(UAPI_CLIENT_SECRET_REF_KIND, schemaName,
(clientSecret, password) -> getTargetState().loadOrBuildSecret(clientSecret, Map.of(
ClientSecretRef.DEFAULT_PASSWORD_KEY, password,
ClientSecretRef.DEFAULT_SCHEMA_KEY, schemaName,
ClientSecretRef.DEFAULT_USERNAME_KEY, schemaName
))
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@

import com.tsystemsmms.cmcc.cmccoperator.components.HasJdbcClient;
import com.tsystemsmms.cmcc.cmccoperator.components.HasService;
import com.tsystemsmms.cmcc.cmccoperator.components.HasUapiClient;
import com.tsystemsmms.cmcc.cmccoperator.crds.ClientSecretRef;
import com.tsystemsmms.cmcc.cmccoperator.crds.ComponentSpec;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.CustomResourceConfigError;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.DefaultClientSecret;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.ClientSecret;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.TargetState;
import com.tsystemsmms.cmcc.cmccoperator.utils.EnvVarSet;
import io.fabric8.kubernetes.api.model.*;
Expand All @@ -26,10 +24,7 @@

import java.util.*;

import static com.tsystemsmms.cmcc.cmccoperator.components.HasMongoDBClient.MONGODB_CLIENT_SECRET_REF_KIND;
import static com.tsystemsmms.cmcc.cmccoperator.crds.ClientSecretRef.DEFAULT_PASSWORD_KEY;
import static com.tsystemsmms.cmcc.cmccoperator.crds.ClientSecretRef.DEFAULT_USERNAME_KEY;
import static com.tsystemsmms.cmcc.cmccoperator.utils.Utils.format;
import static com.tsystemsmms.cmcc.cmccoperator.utils.Utils.EnvVarSecret;

@Slf4j
public class ContentServerComponent extends CorbaComponent implements HasJdbcClient, HasService {
Expand Down Expand Up @@ -122,6 +117,18 @@ public EnvVarSet getEnvVars() {
break;
}

for (ClientSecret cs : getTargetState().getClientSecrets(UAPI_CLIENT_SECRET_REF_KIND).values()) {
Secret secret = cs.getSecret().orElseThrow(() -> new CustomResourceConfigError("Unable to find secret for clientSecretRef \"" + cs.getRef().getSecretName() + "\""));
String username = secret.getStringData().get(cs.getRef().getUsernameKey());
if (cs.getRef().getUsernameKey() == null || username == null) {
throw new CustomResourceConfigError("Secret \"" + secret.getMetadata().getName()
+ "\" does not contain the field \"" + cs.getRef().getUsernameKey()
+ "\" for the username, or it is null");
}
env.add(EnvVarSecret("CAP_SERVER_INITIALPASSWORD_" + username.toUpperCase(Locale.ROOT),
cs.getRef().getSecretName(), cs.getRef().getPasswordKey()));
}

return env;
}

Expand All @@ -140,20 +147,6 @@ public Map<String, String> getSpringBootProperties() {
properties.put("replicator.publication-ior-url", getTargetState().getServiceUrlFor("content-server", "mls"));
}

properties.putAll(getPasswordsAsProperties());

return properties;
}

public Map<String, String> getPasswordsAsProperties() {
Map<String, DefaultClientSecret> secrets = getTargetState().getDefaultClientSecrets(UAPI_CLIENT_SECRET_REF_KIND);
Map<String, String> properties = new HashMap<>();

for (DefaultClientSecret dcs : secrets.values()) {
Map<String, String> data = dcs.getSecret().getStringData();
properties.put("cap.server.initialPassword." + data.get(DEFAULT_USERNAME_KEY),
data.get(DEFAULT_PASSWORD_KEY));
}
return properties;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@

import com.tsystemsmms.cmcc.cmccoperator.components.AbstractComponent;
import com.tsystemsmms.cmcc.cmccoperator.components.HasService;
import com.tsystemsmms.cmcc.cmccoperator.crds.ClientSecretRef;
import com.tsystemsmms.cmcc.cmccoperator.crds.ComponentSpec;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.CustomResourceConfigError;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.DefaultClientSecret;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.ClientSecret;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.TargetState;
import com.tsystemsmms.cmcc.cmccoperator.utils.EnvVarSet;
import io.fabric8.kubernetes.api.model.*;
Expand Down Expand Up @@ -45,12 +44,11 @@ public MongoDBComponent(KubernetesClient kubernetesClient, TargetState targetSta

@Override
public void requestRequiredResources() {
String name = getTargetState().getSecretName(MONGODB_CLIENT_SECRET_REF_KIND, MONGODB_ROOT_USERNAME);
getTargetState().getClientSecretRef(MONGODB_CLIENT_SECRET_REF_KIND, MONGODB_ROOT_USERNAME, password ->
new DefaultClientSecret(ClientSecretRef.defaultClientSecretRef(name), getTargetState().loadOrBuildSecret(name, Map.of(
getTargetState().getClientSecretRef(MONGODB_CLIENT_SECRET_REF_KIND, MONGODB_ROOT_USERNAME,
(clientSecret, password) -> getTargetState().loadOrBuildSecret(clientSecret, Map.of(
DEFAULT_PASSWORD_KEY, password,
DEFAULT_USERNAME_KEY, MONGODB_ROOT_USERNAME
)))
))
);
}

Expand Down Expand Up @@ -180,26 +178,26 @@ List<HasMetadata> buildExtraConfigMaps() {
}

public static Map<String, String> createUsersFromClientSecrets(TargetState targetState) {
Map<String, DefaultClientSecret> secrets = targetState.getDefaultClientSecrets(MONGODB_CLIENT_SECRET_REF_KIND);
Map<String, ClientSecret> secrets = targetState.getClientSecrets(MONGODB_CLIENT_SECRET_REF_KIND);

if (secrets == null) {
log.warn("No MongoDB users to be created");
return Collections.emptyMap();
}

StringBuilder createUsersJs = new StringBuilder();
DefaultClientSecret root = secrets.get(MONGODB_ROOT_USERNAME);
if (root == null)
ClientSecret rootClientSecret = secrets.get(MONGODB_ROOT_USERNAME);
if (rootClientSecret == null)
throw new CustomResourceConfigError("No secret available for MongoDB root user");

// log in as root
Map<String, String> rootDetails = root.getSecret().getStringData();
Map<String, String> rootData = rootClientSecret.getStringData();
createUsersJs.append("db = db.getSiblingDB('admin');\n");
createUsersJs.append(format("db.auth('{}', '{}');\n",
rootDetails.get(DEFAULT_USERNAME_KEY), rootDetails.get(DEFAULT_PASSWORD_KEY)));
rootData.get(DEFAULT_USERNAME_KEY), rootData.get(DEFAULT_PASSWORD_KEY)));

for (DefaultClientSecret dcs : secrets.values()) {
Map<String, String> data = dcs.getSecret().getStringData();
for (ClientSecret cs : secrets.values()) {
Map<String, String> data = cs.getStringData();
if (data.get(DEFAULT_USERNAME_KEY).equals(MONGODB_ROOT_USERNAME))
continue;
// we would like to give client only rights to a specific database, but CM requires the right to create multiple databases (or somehow know which DBs will be created; the list is undocumented, however.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import com.tsystemsmms.cmcc.cmccoperator.crds.ClientSecretRef;
import com.tsystemsmms.cmcc.cmccoperator.crds.ComponentSpec;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.CustomResourceConfigError;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.DefaultClientSecret;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.ClientSecret;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.TargetState;
import com.tsystemsmms.cmcc.cmccoperator.utils.EnvVarSet;
import io.fabric8.kubernetes.api.model.*;
Expand Down Expand Up @@ -44,12 +44,11 @@ public MySQLComponent(KubernetesClient kubernetesClient, TargetState targetState

@Override
public void requestRequiredResources() {
String name = getTargetState().getSecretName(getComponentSpec().getType(), MYSQL_ROOT_USERNAME);
getTargetState().getClientSecretRef(getComponentSpec().getType(), MYSQL_ROOT_USERNAME, password ->
new DefaultClientSecret(ClientSecretRef.defaultClientSecretRef(name), getTargetState().loadOrBuildSecret(name, Map.of(
getTargetState().getClientSecretRef(getComponentSpec().getType(), MYSQL_ROOT_USERNAME,
(clientSecret, password) -> getTargetState().loadOrBuildSecret(clientSecret, Map.of(
ClientSecretRef.DEFAULT_PASSWORD_KEY, password,
ClientSecretRef.DEFAULT_USERNAME_KEY, MYSQL_ROOT_USERNAME
)))
))
);
}

Expand Down Expand Up @@ -181,15 +180,15 @@ List<HasMetadata> buildExtraConfigMaps() {
}

public static Map<String, String> createUsersFromClientSecrets(TargetState targetState) {
Map<String, DefaultClientSecret> secrets = targetState.getDefaultClientSecrets(JDBC_CLIENT_SECRET_REF_KIND);
Map<String, ClientSecret> secrets = targetState.getClientSecrets(JDBC_CLIENT_SECRET_REF_KIND);

if (secrets == null) {
throw new CustomResourceConfigError("No MySQL users to be created");
}

StringBuilder sql = new StringBuilder();
for (DefaultClientSecret dcs : secrets.values()) {
Map<String, String> data = dcs.getSecret().getStringData();
for (ClientSecret cs : secrets.values()) {
Map<String, String> data = cs.getStringData();
if (data.get(ClientSecretRef.DEFAULT_USERNAME_KEY).equals(MYSQL_ROOT_USERNAME))
continue;
sql.append(format("CREATE SCHEMA IF NOT EXISTS {} CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;\n", data.get(ClientSecretRef.DEFAULT_SCHEMA_KEY)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ public class JobReconciler implements Reconciler {
@Override
public void reconcile(KubernetesClient kubernetesClient, String namespace, HasMetadata resource) {
Resource<Job> existing = kubernetesClient.batch().v1().jobs().inNamespace(namespace).withName(resource.getMetadata().getName());
if (existing.get() != null) {
// log.debug("skipping {}/{}", resource.getKind(), resource.getMetadata().getName());
} else {
// log.debug("reconciling {}/{}", resource.getKind(), resource.getMetadata().getName());
if (existing.get() == null) {
log.debug("starting {}/{}", resource.getKind(), resource.getMetadata().getName());
kubernetesClient.resource(resource).inNamespace(namespace).createOrReplace();
}
}
Expand Down
Loading

0 comments on commit ec44967

Please sign in to comment.