diff --git a/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/impl/AddedHandlerUtil.java b/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/impl/AddedHandlerUtil.java index 03eb81dd..c39630d6 100644 --- a/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/impl/AddedHandlerUtil.java +++ b/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/impl/AddedHandlerUtil.java @@ -342,7 +342,7 @@ public static void addInitContainers(String correlationId, TheiaCloudClient clie } } - public static Volume createVolume(String pvcName) { + public static Volume createUserDataVolume(String pvcName) { Volume volume = new Volume(); volume.setName(USER_DATA); PersistentVolumeClaimVolumeSource persistentVolumeClaim = new PersistentVolumeClaimVolumeSource(); @@ -351,7 +351,7 @@ public static Volume createVolume(String pvcName) { return volume; } - public static VolumeMount createVolumeMount(AppDefinitionSpec appDefinition) { + public static VolumeMount createUserDataVolumeMount(AppDefinitionSpec appDefinition) { VolumeMount volumeMount = new VolumeMount(); volumeMount.setName(AddedHandlerUtil.USER_DATA); volumeMount.setMountPath(TheiaCloudPersistentVolumeUtil.getMountPath(appDefinition)); diff --git a/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/impl/GitInitOperationHandler.java b/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/impl/GitInitOperationHandler.java index b4f6cdea..f59c200e 100644 --- a/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/impl/GitInitOperationHandler.java +++ b/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/impl/GitInitOperationHandler.java @@ -35,18 +35,26 @@ import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.EnvVar; import io.fabric8.kubernetes.api.model.EnvVarSource; +import io.fabric8.kubernetes.api.model.KeyToPath; import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.SecretKeySelector; +import io.fabric8.kubernetes.api.model.SecretVolumeSource; import io.fabric8.kubernetes.api.model.SecurityContext; +import io.fabric8.kubernetes.api.model.Volume; import io.fabric8.kubernetes.api.model.VolumeMount; import io.fabric8.kubernetes.api.model.apps.Deployment; public class GitInitOperationHandler implements InitOperationHandler { + protected static final String ETC_THEIA_CLOUD_SSH = "/etc/theia-cloud-ssh"; + protected static final String ID_THEIACLOUD = "id_theiacloud"; + protected static final String SSH_PRIVATEKEY = "ssh-privatekey"; + protected static final String SSH_KEY = "ssh-key"; protected static final String PASSWORD = "password"; protected static final String USERNAME = "username"; protected static final String GIT_PROMPT1 = "GIT_PROMPT1"; protected static final String GIT_PROMPT2 = "GIT_PROMPT2"; + protected static final String KUBERNETES_IO_SSH_AUTH = "kubernetes.io/ssh-auth"; protected static final String KUBERNETES_IO_BASIC_AUTH = "kubernetes.io/basic-auth"; protected static final String HTTPS = "https://"; protected static final String HTTP = "http://"; @@ -80,6 +88,7 @@ public void addInitContainer(String correlationId, TheiaCloudClient client, Depl } List initContainers = deployment.getSpec().getTemplate().getSpec().getInitContainers(); + List volumes = deployment.getSpec().getTemplate().getSpec().getVolumes(); Container gitInitContainer = new Container(); initContainers.add(gitInitContainer); @@ -100,7 +109,7 @@ public void addInitContainer(String correlationId, TheiaCloudClient client, Depl securityContext.setRunAsUser(Long.valueOf(appDefinition.getSpec().getUid())); securityContext.setRunAsGroup(Long.valueOf(appDefinition.getSpec().getUid())); - VolumeMount volumeMount = AddedHandlerUtil.createVolumeMount(appDefinition.getSpec()); + VolumeMount volumeMount = AddedHandlerUtil.createUserDataVolumeMount(appDefinition.getSpec()); gitInitContainer.getVolumeMounts().add(volumeMount); String secretName = args.get(2); @@ -131,8 +140,9 @@ public void addInitContainer(String correlationId, TheiaCloudClient client, Depl return; } } else { - /* get SSH Key and password from secret */ - // TODO JF + if (!injectSSHRepoCredentials(correlationId, secret, secretName, repository, gitInitContainer, volumes)) { + return; + } } } @@ -195,6 +205,45 @@ protected boolean injectHTTPRepoCredentials(String correlationId, Secret secret, return true; } + protected boolean injectSSHRepoCredentials(String correlationId, Secret secret, String secretName, + String repository, Container gitInitContainer, List volumes) { + + if (!KUBERNETES_IO_SSH_AUTH.equals(secret.getType())) { + LOGGER.warn(LogMessageUtil.formatLogMessage(correlationId, MessageFormat + .format("Secret with name {0} is not of type {1}.", secretName, KUBERNETES_IO_SSH_AUTH))); + return false; + } + + /* inject password */ + EnvVar envVar = new EnvVar(); + gitInitContainer.getEnv().add(envVar); + envVar.setName(GIT_PROMPT1); + + EnvVarSource envVarSource = new EnvVarSource(); + envVar.setValueFrom(envVarSource); + envVarSource.setSecretKeyRef(new SecretKeySelector(PASSWORD, secretName, false)); + + /* inject ssh key */ + Volume volume = new Volume(); + volumes.add(volume); + volume.setName(SSH_KEY); + SecretVolumeSource secretVolumeSource = new SecretVolumeSource(); + volume.setSecret(secretVolumeSource); + secretVolumeSource.setSecretName(secretName); + KeyToPath keyToPath = new KeyToPath(); + secretVolumeSource.getItems().add(keyToPath); + keyToPath.setKey(SSH_PRIVATEKEY); + keyToPath.setPath(ID_THEIACLOUD); + + VolumeMount volumeMount = new VolumeMount(); + gitInitContainer.getVolumeMounts().add(volumeMount); + volumeMount.setName(SSH_KEY); + volumeMount.setMountPath(ETC_THEIA_CLOUD_SSH); + volumeMount.setReadOnly(true); + + return true; + } + protected static boolean isHTTP(String repository) { String lowerCasedRepo = repository.toLowerCase(Locale.US); return (lowerCasedRepo.startsWith(HTTP) || lowerCasedRepo.startsWith(HTTPS)); diff --git a/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/impl/LazySessionHandler.java b/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/impl/LazySessionHandler.java index 126f584b..0acad173 100644 --- a/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/impl/LazySessionHandler.java +++ b/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/impl/LazySessionHandler.java @@ -335,10 +335,10 @@ protected void createAndApplyDeployment(String correlationId, String sessionReso protected void addVolumeClaim(Deployment deployment, String pvcName, AppDefinitionSpec appDefinition) { PodSpec podSpec = deployment.getSpec().getTemplate().getSpec(); - Volume volume = AddedHandlerUtil.createVolume(pvcName); + Volume volume = AddedHandlerUtil.createUserDataVolume(pvcName); podSpec.getVolumes().add(volume); Container container = TheiaCloudPersistentVolumeUtil.getTheiaContainer(podSpec, appDefinition); - VolumeMount volumeMount = AddedHandlerUtil.createVolumeMount(appDefinition); + VolumeMount volumeMount = AddedHandlerUtil.createUserDataVolumeMount(appDefinition); container.getVolumeMounts().add(volumeMount); } diff --git a/python/git-init/README.md b/python/git-init/README.md index e2c7a21a..8f1dcf10 100644 --- a/python/git-init/README.md +++ b/python/git-init/README.md @@ -58,6 +58,8 @@ docker run --env GIT_PROMPT1=$SSH_PASSWORD -v ~/tmp/ssh/:/etc/theia-cloud-ssh -- ### Create Kubernetes Resources +#### Secret for HTTP(S) auth + ```yaml apiVersion: v1 kind: Secret @@ -74,6 +76,8 @@ stringData: password: pat ``` +#### Example Session for HTTP(S) auth + ```yaml apiVersion: theia.cloud/v5beta kind: Session @@ -96,3 +100,48 @@ spec: - maintenance_1_1_x - foo-theiacloud-io-basic-auth ``` + +#### Secrets for SSH auth + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: foo-theiacloud-io-ssh-auth + namespace: theiacloud + labels: + theiaCloudInit: git + annotations: + theiaCloudUser: foo@theia-cloud.io +type: kubernetes.io/ssh-auth +stringData: + ssh-privatekey: | + -----BEGIN OPENSSH PRIVATE KEY----- + b3B... + password: sshpw +``` + +#### Example Session for SSH auth + +```yaml +apiVersion: theia.cloud/v5beta +kind: Session +metadata: + name: ws-asdfghjkl-theia-cloud-demo-foo-theia-cloud-io-session + namespace: theiacloud +spec: + appDefinition: theia-cloud-demo + envVars: {} + envVarsFromConfigMaps: [] + envVarsFromSecrets: [] + name: ws-asdfghjkl-theia-cloud-demo-foo-theia-cloud-io-session + user: foo@theia-cloud.io + workspace: ws-asdfghjkl-theia-cloud-demo-foo-theia-cloud-io + sessionSecret: 3e68605f-0c6d-4ae5-9816-738f15d34fc9 + initOperations: + - id: git + arguments: + - git@gitlab.eclipse.org:username/my.repository.git + - maintenance_1_1_x + - foo-theiacloud-io-ssh-auth +``` diff --git a/terraform/terraform.md b/terraform/terraform.md index e628f6c0..48c33a52 100644 --- a/terraform/terraform.md +++ b/terraform/terraform.md @@ -61,6 +61,15 @@ terraform apply Point your browser to the `try_now` output value URL printed to the console at the end. +If you want to use non ephemeral workspaces with minikube you have to mount a directory with the expected user id. Please check the existing persisted volume in Minikube for the path.\ +You might have to configure the firewall for mounting. + +```bash +# This mounts the ~/tmp/minikube on the machine running minikube into minkube. +# Check the persisted volume to find the exact /tmp/hostpath-provisioner/theia-cloud/id path +minikube mount ~/tmp/minikube:/tmp/hostpath-provisioner/theia-cloud/a36c30cee-4d97-4097-826a-31ba72734fd0-pvc-ws-asdfghjkl-theia-c/ +``` + #### Destroy Minikube Cluster First remove the persistent volume from the terraform state: