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

Added Github App Credentials support #186

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
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
76 changes: 75 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ node {

### SSH User Private Key

An SSH *private key*, with a *username*.
An SSH *Private Key*, with a *Username*.

- Value: *private key*
- Tags:
Expand Down Expand Up @@ -293,6 +293,80 @@ node {
}
```

#### Github App Credentials (Optional)

Requires *git-source-branch* plugin to create this credential type

A github *private key*, with a *github app id*.

- Value: *content*
- Tags:
- `jenkins:credentials:type` = `githubApp`
- `jenkins:credentials:appid` = *Github App Id*

The private key format used is PKCS#8 (starts with `-----BEGIN PRIVATE KEY-----`).

##### Example

AWS CLI:

```bash
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in pkcs1.key -out pkcs8.key
aws secretsmanager create-secret --name 'githubapp' --secret-string 'file://pkcs8.key' --tags 'Key=jenkins:credentials:type,Value=githubApp' 'Key=jenkins:credentials:appid,Value=11111' --description 'Github App Credentials'
```

Declarative Pipeline:

```groovy
pipeline {
agent any
environment {
GITHUB_APP = credentials('githubapp')
}
stages {
stage('Example') {
steps {
echo 'Hello world'
}
}
}
}
```

Scripted Pipeline:

```groovy
node {
withCredentials([usernamePassword(credentialsId: 'githubapp', usernameVariable: 'GITHUBAPP_USR', passwordVariable: 'GITHUBAPP_PSW')]) {
echo 'Hello world'
}
}
```

### SecretSource

The plugin allows JCasC to interpolate string secrets from Secrets Manager.

#### Example

AWS CLI:

```bash
aws secretsmanager create-secret --name 'my-password' --secret-string 'abc123' --description 'Jenkins user password'
```

JCasC:

```yaml
jenkins:
securityRealm:
local:
allowsSignup: false
users:
- id: "foo"
password: "${my-password}"
```

## Advanced Usage

You may need to deal with multi-field credentials or vendor-specific credential types that the plugin does not (yet) support.
Expand Down
17 changes: 17 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,18 @@
<version>1.21</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.41</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>github-branch-source</artifactId>
<version>2.9.3</version>
<optional>true</optional>
</dependency>
</dependencies>

<build>
Expand All @@ -146,6 +158,11 @@
</goals>
</execution>
</executions>
<configuration>
<argLine>
-javaagent:"${settings.localRepository}"/org/jmockit/jmockit/1.41/jmockit-1.41.jar
</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import io.jenkins.plugins.credentials.secretsmanager.Messages;
import io.jenkins.plugins.credentials.secretsmanager.factory.certificate.AwsCertificateCredentials;
import io.jenkins.plugins.credentials.secretsmanager.factory.file.AwsFileCredentials;
import io.jenkins.plugins.credentials.secretsmanager.factory.git_app.GitCredentialFactory;
import io.jenkins.plugins.credentials.secretsmanager.factory.ssh_user_private_key.AwsSshUserPrivateKey;
import io.jenkins.plugins.credentials.secretsmanager.factory.string.AwsStringCredentials;
import io.jenkins.plugins.credentials.secretsmanager.factory.username_password.AwsUsernamePasswordCredentials;
Expand Down Expand Up @@ -40,6 +41,7 @@ public static Optional<StandardCredentials> create(String arn, String name, Stri
final String type = tags.getOrDefault(Tags.type, "");
final String username = tags.getOrDefault(Tags.username, "");
final String filename = tags.getOrDefault(Tags.filename, name);
final String appId = tags.getOrDefault(Tags.appid, "");

switch (type) {
case Type.string:
Expand All @@ -52,6 +54,8 @@ public static Optional<StandardCredentials> create(String arn, String name, Stri
return Optional.of(new AwsCertificateCredentials(name, description, new SecretBytesSupplier(client, arn)));
case Type.file:
return Optional.of(new AwsFileCredentials(name, description, filename, new SecretBytesSupplier(client, arn)));
case Type.githubApp:
return GitCredentialFactory.createCredential(name, description, appId, new StringSupplier(client, name));
default:
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public abstract class Tags {
public static final String filename = namespace + "filename";
public static final String type = namespace + "type";
public static final String username = namespace + "username";
public static final String appid = namespace + "appid";

private Tags() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public abstract class Type {
public static final String usernamePassword = "usernamePassword";
public static final String sshUserPrivateKey = "sshUserPrivateKey";
public static final String string = "string";
public static final String githubApp = "githubApp";

private Type() {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.jenkins.plugins.credentials.secretsmanager.factory.git_app;

import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.common.StandardCredentials;
import hudson.Extension;
import hudson.util.Secret;
import io.jenkins.plugins.credentials.secretsmanager.factory.Type;
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials;

import java.util.function.Supplier;
import java.util.Optional;
import java.util.logging.Logger;

@Extension(optional = true)
public class GitCredentialFactory {
private static final Logger LOG = Logger.getLogger(GitCredentialFactory.class.getName());

public static Optional<StandardCredentials> createCredential(String name, String description, String appId, Supplier<String> privateKey) {
if (Jenkins.get().getPlugin("github-branch-source") == null) {
LOG.warning("Plugin not installed: github-branch-source. Cannot create type: " + Type.githubApp);
return Optional.empty();
}

Secret secret = Secret.fromString(privateKey.get());

return Optional.of(new GitHubAppCredentials(CredentialsScope.GLOBAL, name, description, appId, secret));
}
}
Loading