Skip to content
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

fix: Add a predefined secret to store credentials #68

Merged
merged 9 commits into from
Aug 17, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.namespace;

import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;

import io.fabric8.kubernetes.api.model.HasMetadata;
Expand Down Expand Up @@ -47,6 +48,8 @@ public abstract class AbstractWorkspaceServiceAccount<
public static final String EXEC_ROLE_NAME = "exec";
public static final String VIEW_ROLE_NAME = "workspace-view";
public static final String METRICS_ROLE_NAME = "workspace-metrics";
public static final String SECRETS_ROLE_NAME = "workspace-secrets";
public static final String CREDENTIALS_SECRET_NAME = "workspace-credentials-secret";

protected final String namespace;
protected final String serviceAccountName;
Expand Down Expand Up @@ -107,44 +110,55 @@ private void ensureImplicitRolesWithBindings(Client k8sClient) {
// exec role
ensureRoleWithBinding(
k8sClient,
EXEC_ROLE_NAME,
singletonList("pods/exec"),
singletonList(""),
singletonList("create"),
buildRole(
EXEC_ROLE_NAME,
singletonList("pods/exec"),
emptyList(),
singletonList(""),
singletonList("create")),
serviceAccountName + "-exec");

// view role
ensureRoleWithBinding(
k8sClient,
VIEW_ROLE_NAME,
Arrays.asList("pods", "services"),
singletonList(""),
singletonList("list"),
buildRole(
VIEW_ROLE_NAME,
Arrays.asList("pods", "services"),
emptyList(),
singletonList(""),
singletonList("list")),
serviceAccountName + "-view");

// metrics role
ensureRoleWithBinding(
k8sClient,
METRICS_ROLE_NAME,
Arrays.asList("pods", "nodes"),
singletonList("metrics.k8s.io"),
Arrays.asList("list", "get", "watch"),
buildRole(
METRICS_ROLE_NAME,
Arrays.asList("pods", "nodes"),
emptyList(),
singletonList("metrics.k8s.io"),
Arrays.asList("list", "get", "watch")),
serviceAccountName + "-metrics");

// credentials-secret role
ensureRoleWithBinding(
k8sClient,
buildRole(
SECRETS_ROLE_NAME,
singletonList("secrets"),
singletonList(CREDENTIALS_SECRET_NAME),
singletonList(""),
Arrays.asList("get", "patch")),
serviceAccountName + "-secrets");
}

private void ensureRoleWithBinding(
Client k8sClient,
String roleName,
List<String> resources,
List<String> apiGroups,
List<String> verbs,
String bindingName) {
ensureRole(k8sClient, roleName, resources, apiGroups, verbs);
private void ensureRoleWithBinding(Client k8sClient, R role, String bindingName) {
ensureRole(k8sClient, role);
//noinspection unchecked
roleBindings
.apply(k8sClient)
.inNamespace(namespace)
.createOrReplace(createRoleBinding(roleName, bindingName, false));
.createOrReplace(createRoleBinding(role.getMetadata().getName(), bindingName, false));
}

/**
Expand Down Expand Up @@ -180,11 +194,16 @@ private void ensureExplicitClusterRoleBindings(Client k8sClient) {
*
* @param name the name of the role
* @param resources the resources the role grants access to
* @param resourceNames specific resource names witch the role grants access to.
* @param verbs the verbs the role allows
* @return the role object for the given type of Client
*/
protected abstract R buildRole(
String name, List<String> resources, List<String> apiGroups, List<String> verbs);
String name,
List<String> resources,
List<String> resourceNames,
List<String> apiGroups,
List<String> verbs);

/**
* Builds a new role binding but does not persist it.
Expand All @@ -209,17 +228,9 @@ private void createWorkspaceServiceAccount(Client k8sClient) {
.build());
}

private void ensureRole(
Client k8sClient,
String name,
List<String> resources,
List<String> apiGroups,
List<String> verbs) {
private void ensureRole(Client k8sClient, R role) {
//noinspection unchecked
roles
.apply(k8sClient)
.inNamespace(namespace)
.createOrReplace(buildRole(name, resources, apiGroups, verbs));
roles.apply(k8sClient).inNamespace(namespace).createOrReplace(role);
}

public interface ClientFactory<C extends KubernetesClient> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_INFRASTRUCTURE_NAMESPACE_ATTRIBUTE;
import static org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta.DEFAULT_ATTRIBUTE;
import static org.eclipse.che.workspace.infrastructure.kubernetes.api.shared.KubernetesNamespaceMeta.PHASE_ATTRIBUTE;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.AbstractWorkspaceServiceAccount.CREDENTIALS_SECRET_NAME;
import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.NamespaceNameValidator.METADATA_NAME_MAX_LENGTH;

import com.google.common.annotations.VisibleForTesting;
Expand All @@ -30,6 +31,8 @@
import com.google.inject.Singleton;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.Namespace;
import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.api.model.SecretBuilder;
import io.fabric8.kubernetes.client.KubernetesClientException;
import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -341,6 +344,25 @@ public KubernetesNamespace getOrCreate(RuntimeIdentity identity) throws Infrastr
labelNamespaces ? namespaceLabels : emptyMap(),
annotateNamespaces ? namespaceAnnotationsEvaluated : emptyMap());

if (namespace
.secrets()
.get()
.stream()
.noneMatch(s -> s.getMetadata().getName().equals(CREDENTIALS_SECRET_NAME))) {
Secret secret =
new SecretBuilder()
.withType("opaque")
.withNewMetadata()
.withName(CREDENTIALS_SECRET_NAME)
.endMetadata()
.build();
clientFactory
.create()
.secrets()
.inNamespace(identity.getInfrastructureNamespace())
.create(secret);
}

if (!isNullOrEmpty(serviceAccountName)) {
KubernetesWorkspaceServiceAccount workspaceServiceAccount =
doCreateServiceAccount(namespace.getWorkspaceId(), namespace.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,20 @@ public List<Secret> get(LabelSelector labelSelector) throws InfrastructureExcept
}
}

/**
* Get all secrets.
*
* @return namespace secrets list
* @throws InfrastructureException when any exception occurs
*/
public List<Secret> get() throws InfrastructureException {
try {
return clientFactory.create(workspaceId).secrets().inNamespace(namespace).list().getItems();
} catch (KubernetesClientException e) {
throw new KubernetesInfrastructureException(e);
}
}

/**
* Deletes all existing secrets.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,19 @@ public KubernetesWorkspaceServiceAccount(

@Override
protected Role buildRole(
String name, List<String> resources, List<String> apiGroups, List<String> verbs) {
String name,
List<String> resources,
List<String> resourceNames,
List<String> apiGroups,
List<String> verbs) {
return new RoleBuilder()
.withNewMetadata()
.withName(name)
.endMetadata()
.withRules(
new PolicyRuleBuilder()
.withResources(resources)
.withResourceNames(resourceNames)
.withApiGroups(apiGroups)
.withVerbs(verbs)
.build())
Expand Down
Loading