Skip to content
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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ You enter your github personal access token to authenticate to vault.

You enter your Vault GCP auth `role` name and `audience`. The JWT will be automatically retrieved from GCE metdata. This requires that Jenkins master is running on a GCE instance.

#### Vault Kubernetes Credential

![Kubernetes Credential](docs/images/kubernetes_credential.png)

You enter your Vault Kubernetes auth `role`. The JWT will be automatically retrieved from the
mounted secret volume (`/var/run/secrets/kubernetes.io/serviceaccount/token`). This assumes,
that the jenkins is running in Kubernetes Pod with a Service Account attached.

#### Vault Token Credential

![Token Credential](docs/images/token_credential.png)
Expand Down
Binary file added docs/images/kubernetes_credential.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.datapipe.jenkins.vault.credentials;

import com.bettercloud.vault.Vault;
import com.bettercloud.vault.VaultException;
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.datapipe.jenkins.vault.exception.VaultPluginException;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.Extension;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Collectors;
import org.kohsuke.stapler.DataBoundConstructor;

public class VaultKubernetesCredential extends AbstractVaultTokenCredential {

private static final String SERVICE_ACCOUNT_TOKEN_PATH = "/var/run/secrets/kubernetes.io/serviceaccount/token";
Copy link
Member

@jetersen jetersen Sep 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This path is not the same as it would be on Windows?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really know that. The windows container support in kubernetes is relatively new and after a quick search I couldn't find any documentation on how the volumes work in windows containers, but I guess as in any regular windows.
The service account token is just a regular secret, so technically it can be mounted on any path even in unix containers. But the Service Account Admission Controller, which manages service accounts in kubernetes, mounts the token on this path by default. link to the documentation

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this option should only be visible if kubernetes secret is detected?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be achieved with isApplicable in the descriptor

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this option should only be visible if kubernetes secret is detected?

Do you mean to only show the VaultKubernetesCredential as option, when the mounted token is detected?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simply a suggestion, don't know if it makes sense. I am fine with the feature as is.


@NonNull
private final String role;

@DataBoundConstructor
public VaultKubernetesCredential(@CheckForNull CredentialsScope scope, @CheckForNull String id,
@CheckForNull String description, @NonNull String role) {
super(scope, id, description);
this.role = role;
}


@Override
@SuppressFBWarnings(value = "DMI_HARDCODED_ABSOLUTE_FILENAME")
public String getToken(Vault vault) {
String jwt;
try {
jwt = Files.lines(Paths.get(SERVICE_ACCOUNT_TOKEN_PATH)).collect(Collectors.joining());
} catch (IOException e) {
throw new VaultPluginException("could not get JWT from Service Account Token", e);
}

try {
return vault
.withRetries(5, 500)
.auth()
.loginByKubernetes(role, jwt)
.getAuthClientToken();
} catch (VaultException e) {
throw new VaultPluginException("could not log in into vault", e);
}
}

@Extension
public static class DescriptorImpl extends BaseStandardCredentialsDescriptor {

@NonNull
@Override
public String getDisplayName() {
return "Vault Kubernetes Credential";
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:st="jelly:stapler">
<f:entry title="Role">
<f:textbox field="role" name="role"/>
</f:entry>
<st:include page="id-and-description" class="${descriptor.clazz}"/>
</j:jelly>