Skip to content
Snippets Groups Projects
Commit 3698957e authored by OZGCloud's avatar OZGCloud
Browse files

OZG-4453 create certificate secret

parent eb680262
Branches
Tags
No related merge requests found
Showing
with 221 additions and 27 deletions
......@@ -32,6 +32,7 @@ public class ElasticsearchReconciler implements Reconciler<OzgCloudElasticsearch
service.createIndexIfMissing(namespace);
service.createSecurityRoleIfMissing(namespace);
service.createSecurityUserIfMissing(namespace, getPassword(secret));
service.createCertificateIfMissing(namespace);
log.info("Reconcile user successful.");
return OzgCloudElasticsearchUpdateControlBuilder.fromResource(resource).withStatus(CustomResourceStatus.OK).build();
} catch (Exception e) {
......@@ -41,7 +42,7 @@ public class ElasticsearchReconciler implements Reconciler<OzgCloudElasticsearch
}
private String getPassword(Secret secret) {
return MapUtils.getString(secret.getStringData(), OzgCloudElasticsearchSecretHelper.SECRET_PASSWORD_FIELD);
return MapUtils.getString(secret.getStringData(), OzgCloudElasticsearchSecretHelper.CREDENTIAL_SECRET_PASSWORD_FIELD);
}
UpdateControl<OzgCloudElasticsearchCustomResource> buildExceptionUpdateControl(OzgCloudElasticsearchCustomResource resource, Exception e) {
......
......@@ -28,5 +28,7 @@ public class OzgCloudElasticsearchProperties {
private String host;
private int port;
private String scheme;
private String certificateSecretName;
private String certificateSecretDataKey;
}
}
\ No newline at end of file
......@@ -13,10 +13,13 @@ import lombok.RequiredArgsConstructor;
public class OzgCloudElasticsearchSecretHelper {
static final String SECRET_TYPE = "Opaque";
static final String SECRET_ADDRESS_FIELD = "address";
static final String SECRET_INDEX_FIELD = "index";
static final String SECRET_PASSWORD_FIELD = "password";
static final String SECRET_USERNAME_FIELD = "username";
static final String CREDENTIAL_SECRET_ADDRESS_FIELD = "address";
static final String CREDENTIAL_SECRET_INDEX_FIELD = "index";
static final String CREDENTIAL_SECRET_PASSWORD_FIELD = "password";
static final String CREDENTIAL_SECRET_USERNAME_FIELD = "username";
static final String CERTIFICATE_SECRET_DATA_KEY = "ca.crt";
static final int PASSWORD_LENGTH = 15;
......@@ -26,10 +29,10 @@ public class OzgCloudElasticsearchSecretHelper {
return new SecretBuilder()
.withType(SECRET_TYPE)
.withMetadata(createMetaData(name, namespace))
.addToStringData(SECRET_ADDRESS_FIELD, buildSecretAddress())
.addToStringData(SECRET_INDEX_FIELD, namespace)
.addToStringData(SECRET_PASSWORD_FIELD, generatePassword())
.addToStringData(SECRET_USERNAME_FIELD, namespace)
.addToStringData(CREDENTIAL_SECRET_ADDRESS_FIELD, buildSecretAddress())
.addToStringData(CREDENTIAL_SECRET_INDEX_FIELD, namespace)
.addToStringData(CREDENTIAL_SECRET_PASSWORD_FIELD, generatePassword())
.addToStringData(CREDENTIAL_SECRET_USERNAME_FIELD, namespace)
.build();
}
......@@ -41,6 +44,14 @@ public class OzgCloudElasticsearchSecretHelper {
return RandomStringUtils.randomAlphabetic(PASSWORD_LENGTH);
}
public Secret buildCertificateSecret(String namespace, String data) {
return new SecretBuilder()
.withType(SECRET_TYPE)
.withMetadata(createMetaData(properties.getCertificateSecretName(), namespace))
.addToStringData(CERTIFICATE_SECRET_DATA_KEY, data)
.build();
}
private ObjectMeta createMetaData(String name, String namespace) {
var metadata = new ObjectMeta();
metadata.setName(name);
......
......@@ -2,6 +2,7 @@ package de.ozgcloud.operator;
import java.util.Objects;
import org.apache.commons.collections.MapUtils;
import org.springframework.stereotype.Component;
import de.ozgcloud.operator.PutRoleRequestData.IndicesPrivilegesData;
......@@ -37,7 +38,6 @@ public class OzgCloudElasticsearchService {
createCredentialSecret(secretResource, namespace);
log.info("Secret creation successful.");
}
log.info("Secret already exists, return existing.");
return secretResource.get();
} catch (Exception e) {
log.info("Secret creation failed: " + e);
......@@ -53,10 +53,6 @@ public class OzgCloudElasticsearchService {
createAdapter(resource).create(secretHelper.buildCredentialSecret(namespace, properties.getSecretCredentialsName()));
}
ResourceAdapter<Secret> createAdapter(Resource<Secret> resource) {
return new ResourceAdapter<Secret>(resource);
}
// curl -k -X PUT -u elastic:$ELASTICSEARCH_PASSWORD -H 'Content-Type: application/json' 'https://ozg-search-cluster-es-http:9200/'$ES_NS_USER
public void createIndexIfMissing(String name) throws Exception {
log.info("Check index...");
......@@ -121,4 +117,34 @@ public class OzgCloudElasticsearchService {
}
log.info("Delete index role successful.");
}
public void createCertificateIfMissing(String namespace) {
try {
log.info("Create certificate secret if missing...");
var secretResource = kubernetesService.getSecretResource(namespace, properties.getCertificateSecretName());
if(Objects.isNull(secretResource.get())) {
log.info("create...");
createCredentialSecret(namespace, secretResource);
log.info("create successful.");
}
} catch(Exception e) {
log.info("Certificate secret creation failed: " + e);
throw e;
}
}
void createCredentialSecret(String namespace, Resource<Secret> secretResource) {
var serverSecretResource = kubernetesService.getSecretResource(properties.getServerProperties().getNamespace(), properties.getServerProperties().getCertificateSecretName());
createAdapter(secretResource).create(secretHelper.buildCertificateSecret(namespace, getSecretData(serverSecretResource.get())));
}
private String getSecretData(Secret secret) {
return MapUtils.getString(secret.getStringData(), properties.getServerProperties().getCertificateSecretDataKey());
}
ResourceAdapter<Secret> createAdapter(Resource<Secret> resource) {
return new ResourceAdapter<Secret>(resource);
}
}
\ No newline at end of file
......@@ -10,6 +10,7 @@ ozgcloud:
port: 9200
scheme: https
certificateSecretName: elasticsearch-certificate
certificateSecretDataKey: tlsCrt
management:
server:
......
......@@ -37,7 +37,7 @@ class ElasticsearchReconcilerTest {
private final OzgCloudElasticsearchCustomResource resource = ElasticsearchCustomResourceTestFactory.create();
private final static String PASSWORD = "dummyPassword";
private final Secret secret = SecretTestFactory.createBuilder().addToStringData(OzgCloudElasticsearchSecretHelper.SECRET_PASSWORD_FIELD, PASSWORD).build();
private final Secret secret = SecretTestFactory.createBuilder().addToStringData(OzgCloudElasticsearchSecretHelper.CREDENTIAL_SECRET_PASSWORD_FIELD, PASSWORD).build();
@DisplayName("process flow")
@Nested
......@@ -57,7 +57,7 @@ class ElasticsearchReconcilerTest {
@SneakyThrows
@Test
void shouldCheckIndex() {
void shouldCreateIndexIfMissing() {
reconcile();
verify(service).createIndexIfMissing(NamespaceTestFactory.NAMESPACE);
......@@ -65,7 +65,7 @@ class ElasticsearchReconcilerTest {
@SneakyThrows
@Test
void shouldCheckSecurityRole() {
void shouldCreateecurityRoleIfMissing() {
reconcile();
verify(service).createSecurityRoleIfMissing(NamespaceTestFactory.NAMESPACE);
......@@ -73,11 +73,19 @@ class ElasticsearchReconcilerTest {
@SneakyThrows
@Test
void shouldCheckSecurityUser() {
void shouldCallCreateSecurityUserIfMissing() {
reconcile();
verify(service).createSecurityUserIfMissing(NamespaceTestFactory.NAMESPACE, PASSWORD);
}
@SneakyThrows
@Test
void shouldCallCreateCertificateIfMissing() {
reconcile();
verify(service).createCertificateIfMissing(NamespaceTestFactory.NAMESPACE);
}
}
@DisplayName("on exception")
......
......@@ -3,6 +3,8 @@ package de.ozgcloud.operator;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
......@@ -16,7 +18,7 @@ import de.ozgcloud.operator.common.kubernetes.NamespaceTestFactory;
import de.ozgcloud.operator.common.kubernetes.SecretTestFactory;
import io.fabric8.kubernetes.api.model.Secret;
class ElasticsearchSecretBuilderTest {
class OzgCloudElasticsearchSecretHelperTest {
@Spy
@InjectMocks
......@@ -75,7 +77,7 @@ class ElasticsearchSecretBuilderTest {
void shouldBeSet() {
var secret = buildCredentialSecret();
assertThat(secret.getStringData()).containsEntry(OzgCloudElasticsearchSecretHelper.SECRET_ADDRESS_FIELD, String.format("%s:%s", HOST, PORT));
assertThat(secret.getStringData()).containsEntry(OzgCloudElasticsearchSecretHelper.CREDENTIAL_SECRET_ADDRESS_FIELD, String.format("%s:%s", HOST, PORT));
}
@Test
......@@ -97,26 +99,73 @@ class ElasticsearchSecretBuilderTest {
void shouldContainIndex() {
var secret = buildCredentialSecret();
assertThat(secret.getStringData()).containsEntry(OzgCloudElasticsearchSecretHelper.SECRET_INDEX_FIELD, NamespaceTestFactory.NAMESPACE);
assertThat(secret.getStringData()).containsEntry(OzgCloudElasticsearchSecretHelper.CREDENTIAL_SECRET_INDEX_FIELD, NamespaceTestFactory.NAMESPACE);
}
@Test
void shouldContainPassword() {
var secret = buildCredentialSecret();
assertThat(secret.getStringData()).containsKey(OzgCloudElasticsearchSecretHelper.SECRET_PASSWORD_FIELD);
assertThat(secret.getStringData().get(OzgCloudElasticsearchSecretHelper.SECRET_PASSWORD_FIELD)).isNotNull();
assertThat(secret.getStringData()).containsKey(OzgCloudElasticsearchSecretHelper.CREDENTIAL_SECRET_PASSWORD_FIELD);
assertThat(secret.getStringData().get(OzgCloudElasticsearchSecretHelper.CREDENTIAL_SECRET_PASSWORD_FIELD)).isNotNull();
}
@Test
void shouldContainUsername() {
var secret = buildCredentialSecret();
assertThat(secret.getStringData()).containsEntry(OzgCloudElasticsearchSecretHelper.SECRET_USERNAME_FIELD, NamespaceTestFactory.NAMESPACE);
assertThat(secret.getStringData()).containsEntry(OzgCloudElasticsearchSecretHelper.CREDENTIAL_SECRET_USERNAME_FIELD, NamespaceTestFactory.NAMESPACE);
}
private Secret buildCredentialSecret() {
return builder.buildCredentialSecret(NamespaceTestFactory.NAMESPACE, SecretTestFactory.NAME);
}
}
@DisplayName("Build certificate secret")
@Nested
class TestBuildCertificatSecret {
private static final String DATA = "fgdrgsgreg";
@Test
void shouldHaveType() {
var secret = builder.buildCertificateSecret(NamespaceTestFactory.NAMESPACE, DATA);
assertThat(secret.getType()).isEqualTo(OzgCloudElasticsearchSecretHelper.SECRET_TYPE);
}
@DisplayName("metadata")
@Nested
class TestMetadata {
private static final String CERTIFICATE_SECRET_NAME = "rfgsgrgsr";
@BeforeEach
void mock() {
when(properties.getCertificateSecretName()).thenReturn(CERTIFICATE_SECRET_NAME);
}
@Test
void shouldContainName() {
var secret = builder.buildCertificateSecret(NamespaceTestFactory.NAMESPACE, DATA);
assertThat(secret.getMetadata().getName()).isEqualTo(CERTIFICATE_SECRET_NAME);
}
@Test
void shouldContainNamespace() {
var secret = builder.buildCertificateSecret(NamespaceTestFactory.NAMESPACE, DATA);
assertThat(secret.getMetadata().getNamespace()).isEqualTo(NamespaceTestFactory.NAMESPACE);
}
}
@Test
void shouldHaveCaCrtData() {
var secret = builder.buildCertificateSecret(NamespaceTestFactory.NAMESPACE, DATA);
assertThat(secret.getStringData()).containsExactly(Map.entry(OzgCloudElasticsearchSecretHelper.CERTIFICATE_SECRET_DATA_KEY, DATA));
}
}
}
......@@ -13,6 +13,7 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import de.ozgcloud.operator.OzgCloudElasticsearchProperties.OzgCloudElasticsearchServerProperties;
import de.ozgcloud.operator.common.elasticsearch.ElasticsearchRemoteService;
import de.ozgcloud.operator.common.kubernetes.KubernetesRemoteService;
import de.ozgcloud.operator.common.kubernetes.NamespaceTestFactory;
......@@ -297,7 +298,7 @@ class OzgCloudElasticsearchServiceTest {
@Nested
class TestDeleteIndexIfExists {
private static final String INDEX_NAME = NamespaceTestFactory.NAMESPACE;
private static final String INDEX_NAME = NAMESPACE;
@SneakyThrows
@Test
......@@ -317,4 +318,99 @@ class OzgCloudElasticsearchServiceTest {
verify(remoteService).deleteIndex(INDEX_NAME);
}
}
@DisplayName("Create certificate if missing")
@Nested
class TestCreateCertificateIfMissing {
private static final String CERTIFICATE_NAME = "dummySecretName";
@Mock
private Resource<Secret> secretResource;
@DisplayName("process flow")
@Nested
class TestProcessFlow {
@Mock
private OzgCloudElasticsearchServerProperties serverProperties;
@BeforeEach
void mock() {
when(kubernetesService.getSecretResource(any(), any())).thenReturn(secretResource);
when(properties.getCertificateSecretName()).thenReturn(CERTIFICATE_NAME);
}
@Test
void shouldGetCertificateSecret() {
when(secretResource.get()).thenReturn(SecretTestFactory.create());
service.createCertificateIfMissing(NAMESPACE);
verify(kubernetesService).getSecretResource(NAMESPACE, CERTIFICATE_NAME);
}
@Test
void shouldCreateIfMissing() {
when(secretResource.get()).thenReturn(null);
doNothing().when(service).createCredentialSecret(any(), any());
service.createCertificateIfMissing(NAMESPACE);
verify(service).createCredentialSecret(NAMESPACE, secretResource);
}
}
@DisplayName("create credential secret")
@Nested
class TestCreateCredentialSecret {
private static final String SERVER_NAMESPACE = "";
private static final String SERVER_CERTIFICATE_SECRET_NAME = "";
private static final String SERVER_CERTIFICATE_SECRET_DATA_KEY = "fesfdsfd";
private static final String SERVER_CERTIFICATE_SECRET_DATA = "dsadwadas";
private static final Secret SERVER_CERTIFICATE_SECRET = SecretTestFactory.createBuilder()
.addToStringData(SERVER_CERTIFICATE_SECRET_DATA_KEY, SERVER_CERTIFICATE_SECRET_DATA)
.build();
private static final Secret CREDENTIAL_SECRET = SecretTestFactory.create();
@Mock
private OzgCloudElasticsearchServerProperties serverProperties;
@Mock
private ResourceAdapter<Secret> resourceAdapter;
@BeforeEach
void mock() {
when(properties.getServerProperties()).thenReturn(serverProperties);
when(serverProperties.getNamespace()).thenReturn(SERVER_NAMESPACE);
when(serverProperties.getCertificateSecretName()).thenReturn(SERVER_CERTIFICATE_SECRET_NAME);
when(serverProperties.getCertificateSecretDataKey()).thenReturn(SERVER_CERTIFICATE_SECRET_DATA_KEY);
when(kubernetesService.getSecretResource(any(), any())).thenReturn(secretResource);
when(secretResource.get()).thenReturn(SERVER_CERTIFICATE_SECRET);
doReturn(resourceAdapter).when(service).createAdapter(any());
when(secretHelper.buildCertificateSecret(any(), any())).thenReturn(CREDENTIAL_SECRET);
}
@Test
void shouldGetServerSecret() {
service.createCredentialSecret(NAMESPACE, secretResource);
verify(kubernetesService).getSecretResource(SERVER_NAMESPACE, SERVER_CERTIFICATE_SECRET_NAME);
}
@Test
void shouldBuildSecret() {
service.createCredentialSecret(NAMESPACE, secretResource);
verify(secretHelper).buildCertificateSecret(NAMESPACE, SERVER_CERTIFICATE_SECRET_DATA);
}
@Test
void shouldCreate() {
service.createCredentialSecret(NAMESPACE, secretResource);
verify(resourceAdapter).create(CREDENTIAL_SECRET);
}
}
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment