Skip to content

Instantly share code, notes, and snippets.

@mllrjb
Last active April 10, 2024 17:30
Show Gist options
  • Save mllrjb/ccfd3315b7546ae8e8382ff693b34d7f to your computer and use it in GitHub Desktop.
Save mllrjb/ccfd3315b7546ae8e8382ff693b34d7f to your computer and use it in GitHub Desktop.
Jenkins init.groovy.d role-based authorization strategy

Usage

Set a system environment variable AUTHZ_JSON_URL that points to a JSON file with the following structure:

{
  "admins": [
    "groupA", 
    "userA"
  ],
  "builders": [
    "groupB",
    "userB"
  ],
  "readers": ["anonymous"]
}

If you don't specify a URL, it will just grant admin access to anonymous.

import hudson.*
import hudson.security.*
import jenkins.model.*
import java.util.*
import com.michelin.cio.hudson.plugins.rolestrategy.*
import com.synopsys.arc.jenkins.plugins.rolestrategy.*
import java.lang.reflect.*
import java.util.logging.*
import groovy.json.*
def env = System.getenv()
/**
* ===================================
*
* Roles
*
* ===================================
*/
def globalRoleRead = "read"
def globalBuildRole = "build"
def globalRoleAdmin = "admin"
/**
* ===================================
*
* Users and Groups
*
* ===================================
*/
def access = [
admins: ["anonymous"],
builders: [],
readers: []
]
if (env.AUTHZ_JSON_FILE) {
println "Get role authorizations from file ${env.AUTHZ_JSON_FILE}"
File f = new File(env.AUTHZ_JSON_FILE)
def jsonSlurper = new JsonSlurper()
def jsonText = f.getText()
access = jsonSlurper.parseText( jsonText )
}
else if (env.AUTH_JSON_URL) {
println "Get role authorizations from URL ${env.AUTHZ_JSON_URL}"
URL jsonUrl = new URL(env.AUTHZ_JSON_URL);
access = new JsonSlurper().parse(jsonUrl);
}
else {
println "Warning! Neither env.AUTHZ_JSON_FILE nor env.AUTHZ_JSON_URL specified!"
println "Granting anonymous admin access"
}
/**
* ===================================
*
* Permissions
*
* ===================================
*/
// TODO: drive these from a config file
def adminPermissions = [
"hudson.model.Hudson.Administer",
"hudson.model.Hudson.Read"
]
def readPermissions = [
"hudson.model.Hudson.Read",
"hudson.model.Item.Discover",
"hudson.model.Item.Read"
]
def buildPermissions = [
"hudson.model.Hudson.Read",
"hudson.model.Item.Build",
"hudson.model.Item.Cancel",
"hudson.model.Item.Read",
"hudson.model.Run.Replay"
]
def roleBasedAuthenticationStrategy = new RoleBasedAuthorizationStrategy()
Jenkins.instance.setAuthorizationStrategy(roleBasedAuthenticationStrategy)
/**
* ===================================
*
* HACK
* Inspired by https://issues.jenkins-ci.org/browse/JENKINS-23709
* Deprecated by on https://github.com/jenkinsci/role-strategy-plugin/pull/12
*
* ===================================
*/
Constructor[] constrs = Role.class.getConstructors();
for (Constructor<?> c : constrs) {
c.setAccessible(true);
}
// Make the method assignRole accessible
Method assignRoleMethod = RoleBasedAuthorizationStrategy.class.getDeclaredMethod("assignRole", RoleType.class, Role.class, String.class);
assignRoleMethod.setAccessible(true);
println("HACK! changing visibility of RoleBasedAuthorizationStrategy.assignRole")
/**
* ===================================
*
* Permissions
*
* ===================================
*/
Set<Permission> adminPermissionSet = new HashSet<Permission>();
adminPermissions.each { p ->
def permission = Permission.fromId(p);
if (permission != null) {
adminPermissionSet.add(permission);
} else {
println("${p} is not a valid permission ID (ignoring)")
}
}
Set<Permission> buildPermissionSet = new HashSet<Permission>();
buildPermissions.each { p ->
def permission = Permission.fromId(p);
if (permission != null) {
buildPermissionSet.add(permission);
} else {
println("${p} is not a valid permission ID (ignoring)")
}
}
Set<Permission> readPermissionSet = new HashSet<Permission>();
readPermissions.each { p ->
def permission = Permission.fromId(p);
if (permission != null) {
readPermissionSet.add(permission);
} else {
println("${p} is not a valid permission ID (ignoring)")
}
}
/**
* ===================================
*
* Permissions -> Roles
*
* ===================================
*/
// admins
Role adminRole = new Role(globalRoleAdmin, adminPermissionSet);
roleBasedAuthenticationStrategy.addRole(RoleType.Global, adminRole);
// builders
Role buildersRole = new Role(globalBuildRole, buildPermissionSet);
roleBasedAuthenticationStrategy.addRole(RoleType.Global, buildersRole);
// anonymous read
Role readRole = new Role(globalRoleRead, readPermissionSet);
roleBasedAuthenticationStrategy.addRole(RoleType.Global, readRole);
/**
* ===================================
*
* Roles -> Groups/Users
*
* ===================================
*/
access.admins.each { l ->
println("Granting admin to ${l}")
roleBasedAuthenticationStrategy.assignRole(RoleType.Global, adminRole, l);
}
access.builders.each { l ->
println("Granting builder to ${l}")
roleBasedAuthenticationStrategy.assignRole(RoleType.Global, buildersRole, l);
}
access.readers.each { l ->
println("Granting read to ${l}")
roleBasedAuthenticationStrategy.assignRole(RoleType.Global, readRole, l);
}
Jenkins.instance.save()
{
"admins": [
"groupA",
"userA"
],
"builders": [
"groupB",
"userB"
],
"readers": ["anonymous"]
}
@njesper
Copy link

njesper commented Jul 19, 2019

Thanks a lot! I got it working again :-)

I'm running a modified version of the script, so I had to have a look at the diffs to figure out how to update my version. I don't think I was affected by the if-error, but rather a mistake by me; I only changed RoleBasedAuthorizationStrategy.GLOBAL to RoleType.Global for assignRole, but not for addRole.

  • Looks like this patch is missing in the script in your previous comment ;-)

Big Kudos!

@john-fletcher
Copy link

john-fletcher commented Sep 16, 2019

@mllrjb appriciate your help here.

I tried this script and roles.json file . but this sets security realm / authorization in such a way that I no longer able to login to Jenkins.
"missing overall read permissions"
again i had to false , which again removes the entire security. :(

can you please post latest working script and json file ?

@couturiehe01
Copy link

John-Fletcher,
This script does not manage the authentication part, only the authorization one. Please double check if your issue comes from somewhere else.

@ipeacocks
Copy link

ipeacocks commented May 15, 2020

@couturiehe01 you example helped me a lot! It's more manual than yours but maybe it will be useful for somebody

import hudson.*
import hudson.model.*
import hudson.security.*
import jenkins.*
import jenkins.model.*
import java.util.*
import com.michelin.cio.hudson.plugins.rolestrategy.*
import com.synopsys.arc.jenkins.plugins.rolestrategy.RoleType;
import java.lang.reflect.*
import java.util.logging.*
import groovy.json.*

def env = System.getenv()

// Roles
// def globalRoleRead = "read"
def globalRoleAdmin = "admin"
def globalRoleRemoteAgent = "remote_agent"

def jenkinsInstance = Jenkins.getInstance()
def currentAuthenticationStrategy = Hudson.instance.getAuthorizationStrategy()

Thread.start {
    sleep 15000
    if (currentAuthenticationStrategy instanceof RoleBasedAuthorizationStrategy) {
      println "Role based authorisation already enabled."
      println "Exiting script..."
      return
    } else {
      println "Enabling role based authorisation strategy..."
    }

    // Set new authentication strategy
    RoleBasedAuthorizationStrategy roleBasedAuthenticationStrategy = new RoleBasedAuthorizationStrategy()
    jenkinsInstance.setAuthorizationStrategy(roleBasedAuthenticationStrategy)

    Constructor[] constrs = Role.class.getConstructors();
    for (Constructor<?> c : constrs) {
      c.setAccessible(true);
    }

    // Create admin set of permissions
    Set<Permission> adminPermissions = new HashSet<Permission>();
    adminPermissions.add(Permission.fromId("hudson.model.View.Delete"));
    adminPermissions.add(Permission.fromId("hudson.model.Computer.Connect"));
    adminPermissions.add(Permission.fromId("hudson.model.Run.Delete"));
    adminPermissions.add(Permission.fromId("hudson.model.Hudson.UploadPlugins"));
    adminPermissions.add(Permission.fromId("com.cloudbees.plugins.credentials.CredentialsProvider.ManageDomains"));
    adminPermissions.add(Permission.fromId("hudson.model.Computer.Create"));
    adminPermissions.add(Permission.fromId("hudson.model.View.Configure"));
    adminPermissions.add(Permission.fromId("hudson.model.Hudson.ConfigureUpdateCenter"));
    adminPermissions.add(Permission.fromId("hudson.model.Computer.Build"));
    adminPermissions.add(Permission.fromId("hudson.model.Item.Configure"));
    adminPermissions.add(Permission.fromId("hudson.model.Hudson.Administer"));
    adminPermissions.add(Permission.fromId("hudson.model.Item.Cancel"));
    adminPermissions.add(Permission.fromId("hudson.model.Item.Read"));
    adminPermissions.add(Permission.fromId("com.cloudbees.plugins.credentials.CredentialsProvider.View"));
    adminPermissions.add(Permission.fromId("hudson.model.Computer.Delete"));
    adminPermissions.add(Permission.fromId("hudson.model.Item.Build"));
    adminPermissions.add(Permission.fromId("hudson.scm.SCM.Tag"));
    adminPermissions.add(Permission.fromId("hudson.model.Item.Discover"));
    adminPermissions.add(Permission.fromId("hudson.model.Hudson.Read"));
    adminPermissions.add(Permission.fromId("com.cloudbees.plugins.credentials.CredentialsProvider.Update"));
    adminPermissions.add(Permission.fromId("hudson.model.Item.Create"));
    adminPermissions.add(Permission.fromId("hudson.model.Item.Move"));
    adminPermissions.add(Permission.fromId("hudson.model.Item.Workspace"));
    adminPermissions.add(Permission.fromId("com.cloudbees.plugins.credentials.CredentialsProvider.Delete"));
    adminPermissions.add(Permission.fromId("hudson.model.View.Read"));
    adminPermissions.add(Permission.fromId("hudson.model.Hudson.RunScripts"));
    adminPermissions.add(Permission.fromId("hudson.model.View.Create"));
    adminPermissions.add(Permission.fromId("hudson.model.Item.Delete"));
    adminPermissions.add(Permission.fromId("hudson.model.Computer.Configure"));
    adminPermissions.add(Permission.fromId("com.cloudbees.plugins.credentials.CredentialsProvider.Create"));
    adminPermissions.add(Permission.fromId("hudson.model.Computer.Disconnect"));
    adminPermissions.add(Permission.fromId("hudson.model.Run.Update"));

    // Create the admin Role
    Role adminRole = new Role(globalRoleAdmin, adminPermissions);
    roleBasedAuthenticationStrategy.addRole(RoleType.fromString(RoleBasedAuthorizationStrategy.GLOBAL), adminRole);

    //------------------------------------------------------------------------------------------

    // Create set of permissions for remote_agent
    Set<Permission> remoteAgentPermissions = new HashSet<Permission>();
    remoteAgentPermissions.add(Permission.fromId("hudson.model.Hudson.Read"));
    remoteAgentPermissions.add(Permission.fromId("hudson.model.Computer.Connect"));
    remoteAgentPermissions.add(Permission.fromId("hudson.model.Computer.Create"));
    remoteAgentPermissions.add(Permission.fromId("hudson.model.Computer.Build"));
    remoteAgentPermissions.add(Permission.fromId("hudson.model.Computer.Delete"));
    remoteAgentPermissions.add(Permission.fromId("hudson.model.Computer.Configure"));
    remoteAgentPermissions.add(Permission.fromId("hudson.model.Computer.Disconnect"));

    // Create the Role for remote_agent
    Role remoteAgentRole = new Role(globalRoleRemoteAgent, remoteAgentPermissions);
    roleBasedAuthenticationStrategy.addRole(RoleType.fromString(RoleBasedAuthorizationStrategy.GLOBAL), remoteAgentRole);

    // --------------------------------------------------------------------------------------------------------

    // Creating admin user
    def hudsonRealm = new HudsonPrivateSecurityRealm(false)
    hudsonRealm.createAccount(env.JENKINS_USER, env.JENKINS_PASS)
    jenkinsInstance.setSecurityRealm(hudsonRealm)

    // Assign the role
    roleBasedAuthenticationStrategy.assignRole(RoleType.fromString(RoleBasedAuthorizationStrategy.GLOBAL), adminRole, env.JENKINS_USER);
    println "Admin role created...OK"

    // --------------------------------------------------------------------------------------------------------

    // Creating remote_agent user
    def hudsonRealm_2 = new HudsonPrivateSecurityRealm(false)
    hudsonRealm_2.createAccount(env.JENKINS_RA_USER, env.JENKINS_RA_PASS)
    jenkinsInstance.setSecurityRealm(hudsonRealm_2)

    // Assign the role
    roleBasedAuthenticationStrategy.assignRole(RoleType.fromString(RoleBasedAuthorizationStrategy.GLOBAL), remoteAgentRole, env.JENKINS_RA_USER);
    println "Remote Agent role created...OK"


    // Save the state
    println "Saving changes."
    jenkinsInstance.save()
}

JENKINS_USER is for admin, JENKINS_RA_USER is for remote_agent user (for jenkins agents connecting). Users and pass' are taken from env vars.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment