Skip to content

Store mysql credentials in k8s secret #119

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion samples/mysql-schema/k8s/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ spec:
properties:
spec:
type: object
required:
- encoding
properties:
encoding:
type: string
type: string
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.ConfigBuilder;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.takes.facets.fork.FkRegex;
Expand All @@ -21,8 +22,9 @@ public static void main(String[] args) throws IOException {
log.info("MySQL Schema Operator starting");

Config config = new ConfigBuilder().withNamespace(null).build();
Operator operator = new Operator(new DefaultKubernetesClient(config));
operator.registerControllerForAllNamespaces(new SchemaController());
KubernetesClient client = new DefaultKubernetesClient(config);
Operator operator = new Operator(client);
operator.registerControllerForAllNamespaces(new SchemaController(client));

new FtBasic(
new TkFork(new FkRegex("/health", "ALL GOOD!")), 8080
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@

import com.github.containersolutions.operator.api.Controller;
import com.github.containersolutions.operator.api.ResourceController;
import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.api.model.SecretBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Base64;
import java.util.Optional;

import static java.lang.String.format;
Expand All @@ -17,10 +22,15 @@
crdName = "schemas.mysql.sample.javaoperatorsdk",
customResourceClass = Schema.class)
public class SchemaController implements ResourceController<Schema> {

static final String USERNAME_FORMAT = "%s-user";
static final String SECRET_FORMAT = "%s-secret";

private final Logger log = LoggerFactory.getLogger(getClass());

private final KubernetesClient kubernetesClient;

public SchemaController(KubernetesClient kubernetesClient) { this.kubernetesClient = kubernetesClient; }

@Override
public Optional<Schema> createOrUpdateResource(Schema schema) {
try (Connection connection = getConnection()) {
Expand All @@ -29,14 +39,36 @@ public Optional<Schema> createOrUpdateResource(Schema schema) {
schema.getMetadata().getName(),
schema.getSpec().getEncoding()));

String password = RandomStringUtils.randomAlphanumeric(16);
String userName = String.format(USERNAME_FORMAT,
schema.getMetadata().getName());
String secretName = String.format(SECRET_FORMAT,
schema.getMetadata().getName());
connection.createStatement().execute(format(
"CREATE USER '%1$s' IDENTIFIED BY '%2$s'",
userName, password));
connection.createStatement().execute(format(
"GRANT ALL ON `%1$s`.* TO '%2$s'",
schema.getMetadata().getName(), userName));
Secret credentialsSecret = new SecretBuilder()
.withNewMetadata().withName(secretName).endMetadata()
.addToData("MYSQL_USERNAME", Base64.getEncoder().encodeToString(userName.getBytes()))
.addToData("MYSQL_PASSWORD", Base64.getEncoder().encodeToString(password.getBytes()))
.build();
this.kubernetesClient.secrets()
.inNamespace(schema.getMetadata().getNamespace())
.create(credentialsSecret);

SchemaStatus status = new SchemaStatus();
status.setUrl(format("jdbc:mysql://%1$s/%2$s",
System.getenv("MYSQL_HOST"),
schema.getMetadata().getName()));
status.setUserName(userName);
status.setSecretName(secretName);
status.setStatus("CREATED");
schema.setStatus(status);

log.info("Schema {} created", schema.getMetadata().getName());

return Optional.of(schema);
}
return Optional.empty();
Expand All @@ -45,6 +77,8 @@ public Optional<Schema> createOrUpdateResource(Schema schema) {

SchemaStatus status = new SchemaStatus();
status.setUrl(null);
status.setUserName(null);
status.setSecretName(null);
status.setStatus("ERROR");
schema.setStatus(status);

Expand All @@ -60,6 +94,16 @@ public boolean deleteResource(Schema schema) {
if (schemaExists(connection, schema.getMetadata().getName())) {
connection.createStatement().execute("DROP DATABASE `" + schema.getMetadata().getName() + "`");
log.info("Deleted Schema '{}'", schema.getMetadata().getName());

if (userExists(connection, schema.getStatus().getUserName())) {
connection.createStatement().execute("DROP USER '" + schema.getStatus().getUserName() + "'");
log.info("Deleted User '{}'", schema.getStatus().getUserName());
}

this.kubernetesClient.secrets()
.inNamespace(schema.getMetadata().getNamespace())
.withName(schema.getStatus().getSecretName())
.delete();
} else {
log.info("Delete event ignored for schema '{}', real schema doesn't exist",
schema.getMetadata().getName());
Expand All @@ -86,4 +130,10 @@ private boolean schemaExists(Connection connection, String schemaName) throws SQ
return resultSet.first();
}

private boolean userExists(Connection connection, String userName) throws SQLException {
ResultSet resultSet = connection.createStatement().executeQuery(
format("SELECT User FROM mysql.user WHERE User='%1$s'", userName)
);
return resultSet.first();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ public String getEncoding() {
public void setEncoding(String encoding) {
this.encoding = encoding;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ public class SchemaStatus {

private String status;

private String userName;

private String secretName;

public String getUrl() {
return url;
}
Expand All @@ -21,4 +25,12 @@ public String getStatus() {
public void setStatus(String status) {
this.status = status;
}

public String getUserName() { return userName; }

public void setUserName(String userName) { this.userName = userName; }

public String getSecretName() { return secretName; }

public void setSecretName(String secretName) { this.secretName = secretName; }
}