From 4f489464e9ec53e42ba9cd4bea09f7e95f4444bb Mon Sep 17 00:00:00 2001 From: Sayali Gaikawad Date: Thu, 5 Dec 2024 18:21:09 -0800 Subject: [PATCH] Refactor Signed-off-by: Sayali Gaikawad --- README.md | 32 ++++++++++++++++++-------------- bin/ci-stack.ts | 6 +++--- lib/ci-stack.ts | 6 +++--- lib/compute/auth-config.ts | 18 +++++++++--------- lib/compute/jenkins-main-node.ts | 7 ++++--- test/compute/auth-config.test.ts | 10 +++++----- 6 files changed, 42 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 8a4c7492..cf65da26 100644 --- a/README.md +++ b/README.md @@ -81,20 +81,21 @@ $aws secretsmanager put-secret-value \ ### Executing Optional Tasks #### Construct Props -| Name | Type | Description | -|-----------------------------------------------------------|:---------|:-----------------------------------------------------------------------------------------| -| [useSsl](#ssl-configuration) | boolean | Should the Jenkins use https | -| [restrictServerAccessTo](#restricting-server-access) | Ipeer | Restrict jenkins server access | -| [authType](#setup-authentication-using-openid-connect-oidc-or-github-authentication) | string | Authentication type for Jenkins login. Acceptable values: github, oidc, default | -| [ignoreResourcesFailures](#ignore-resources-failure) | boolean | Additional verification during deployment and resource startup | -| [adminUsers](#setup-authentication-using-openid-connect-oidc-or-github-authentication) | string[] | List of users with admin access during initial deployment | -| [additionalCommands](#runnning-additional-commands) | string | Additional logic that needs to be run on Master Node. The value has to be path to a file | -| [dataRetention](#data-retention) | boolean | Do you want to retain jenkins jobs and build history | -| [agentAssumeRole](#assume-role) | string | IAM role ARN to be assumed by jenkins agent nodes | -| [envVarsFilePath](#add-environment-variables) | string | Path to file containing env variables in the form of key value pairs | -| [macAgent](#mac-agents) | boolean | Add mac agents to jenkins | -| [useProdAgents](#use-production-agents) | boolean | Should jenkins server use production agents | -| [enableViews](#enable-views) | boolean | Adds Build, Test, Release and Misc views to Jenkins Dashboard . Defaults to false | +| Name | Type | Description | +|----------------------------------------------------------------------------------------|:---------|:---------------------------------------------------------------------------------------------------------------------------| +| [useSsl](#ssl-configuration) | boolean | Should the Jenkins use https | +| [restrictServerAccessTo](#restricting-server-access) | Ipeer | Restrict jenkins server access | +| [authType](#setup-authentication-using-openid-connect-oidc-or-github-authentication) | string | Authentication type for Jenkins login. Acceptable values: github, oidc, default | +| [ignoreResourcesFailures](#ignore-resources-failure) | boolean | Additional verification during deployment and resource startup | +| [adminUsers](#setup-authentication-using-openid-connect-oidc-or-github-authentication) | string[] | List of users with admin access during initial deployment | +| [additionalCommands](#runnning-additional-commands) | string | Additional logic that needs to be run on Master Node. The value has to be path to a file | +| [dataRetention](#data-retention) | boolean | Do you want to retain jenkins jobs and build history | +| [agentAssumeRole](#assume-role) | string | IAM role ARN to be assumed by jenkins agent nodes | +| [envVarsFilePath](#add-environment-variables) | string | Path to file containing env variables in the form of key value pairs | +| [macAgent](#mac-agents) | boolean | Add mac agents to jenkins | +| [useProdAgents](#use-production-agents) | boolean | Should jenkins server use production agents | +| [enableViews](#enable-views) | boolean | Adds Build, Test, Release and Misc views to Jenkins Dashboard . Defaults to false | +| [FineGrainedAccessSpecs](#fine-grained-access) | FineGrainedAccessSpecs | Add specifications for fine grained access contol. See [FineGrainedAccessSpecs](lib/compute/auth-config.ts) for more details | #### SSL Configuration 1. Locate the secret manager arns in the ci-config-stack outputs 1. Update the secret value ([see docs](https://docs.aws.amazon.com/cli/latest/reference/secretsmanager/put-secret-value.html)) for the `certContentsSecret` with the certificate contents @@ -264,6 +265,9 @@ Views on Jenkins dashboard allows us to classify jobs into different sections. B The `All` is the default view and contains all the jobs. +#### Fine Grained Access +Apart from global admin and read-only access, users can be given fine-grained access for specific workflows/folder. The access is set up using role based strategy plugin. The construct props should be of type [FineGrainedAccessSpecs](./lib/compute/auth-config.ts). Check the details for specifying [patterns](https://plugins.jenkins.io/role-strategy/#plugin-content-configuring-roles). Currently, this code base only adds `builder-template` that allows to build jobs. For adding more templates, please contribute. + ### Troubleshooting #### Main Node Useful links diff --git a/bin/ci-stack.ts b/bin/ci-stack.ts index a08618d9..54304180 100644 --- a/bin/ci-stack.ts +++ b/bin/ci-stack.ts @@ -25,18 +25,18 @@ const ciStack = new CIStack(app, `OpenSearch-CI-${defaultEnv}`, { useSsl: true, adminUsers: ['gaiksaya'], authType: 'github', - fineGrainAccessSpecs: [ + fineGrainedAccessSpecs: [ { users: ['gaiksaya', 'sayaligaikawad'], roleName: 'temp-role', pattern: '.*', - template: 'builder-template', + templateName: 'builder-template', }, { users: ['foo', 'bar'], roleName: 'temp-role-2', pattern: '(?)integ*', - template: 'builder-template', + templateName: 'builder-template', }, ], restrictServerAccessTo: Peer.prefixList('pl-f8a64391'), diff --git a/lib/ci-stack.ts b/lib/ci-stack.ts index 74f33bf4..f0c04808 100644 --- a/lib/ci-stack.ts +++ b/lib/ci-stack.ts @@ -26,7 +26,7 @@ import { JenkinsMonitoring } from './monitoring/ci-alarms'; import { JenkinsExternalLoadBalancer } from './network/ci-external-load-balancer'; import { JenkinsSecurityGroups } from './security/ci-security-groups'; import { JenkinsWAF } from './security/waf'; -import { FineGrainAccessSpecs } from './compute/auth-config'; +import { FineGrainedAccessSpecs } from './compute/auth-config'; export interface CIStackProps extends StackProps { /** Additional logic that needs to be run on Master Node. The value has to be path to a file */ @@ -38,7 +38,7 @@ export interface CIStackProps extends StackProps { /** Type of login mechanism to adopt */ readonly authType?: string; /** Fine grain access control specifications */ - readonly fineGrainAccessSpecs?: FineGrainAccessSpecs[]; + readonly fineGrainedAccessSpecs?: FineGrainedAccessSpecs[]; /** Do you want to retain jenkins jobs and build history */ readonly dataRetention?: boolean; /** Enable views on jenkins UI */ @@ -193,7 +193,7 @@ export class CIStack extends Stack { authCredsSecretsArn: importedAuthConfigValuesSecretBucketValue.toString(), useSsl, authType, - fineGrainAccessSpecs: props?.fineGrainAccessSpecs, + fineGrainedAccessSpecs: props?.fineGrainedAccessSpecs, failOnCloudInitError: props?.ignoreResourcesFailures, adminUsers: props?.adminUsers, agentNodeSecurityGroup: this.securityGroups.agentNodeSG.securityGroupId, diff --git a/lib/compute/auth-config.ts b/lib/compute/auth-config.ts index c2778dd6..96efc793 100644 --- a/lib/compute/auth-config.ts +++ b/lib/compute/auth-config.ts @@ -8,11 +8,11 @@ import { writeFileSync } from 'fs'; * this file be licensed under the Apache-2.0 license or a * compatible open source license. */ -export interface FineGrainAccessSpecs { +export interface FineGrainedAccessSpecs { users: string[], roleName: string, pattern: string, - template: string + templateName: string } export class AuthConfig { @@ -70,10 +70,10 @@ export class AuthConfig { 'View/Read', ]; - public static addOidcConfigToJenkinsYaml(yamlObject: any, authType: string, admins?: string[], fineGrainAccessItems?: FineGrainAccessSpecs[]): any { + public static addOidcConfigToJenkinsYaml(yamlObject: any, authType: string, admins?: string[], fineGrainedAccessItems?: FineGrainedAccessSpecs[]): any { const jenkinsYaml: any = yamlObject; let adminUsers: string[] = ['admin']; - const readOnlyUsers: string[] = ['anonymous']; + const readOnlyUsers: string[] = ['anonymous', 'authenticated']; if (admins) { adminUsers = adminUsers.concat(admins); @@ -109,10 +109,10 @@ export class AuthConfig { const rolesAndPermissions: { [x: string]: any; } = { roleBased: { - permissionTemplates: { + permissionTemplates: [{ name: 'builder-template', permissions: AuthConfig.builderTemplatePermissions, - }, + }], roles: { global: [{ entries: adminUsers.map((user) => ({ user })), @@ -133,12 +133,12 @@ export class AuthConfig { }; jenkinsYaml.jenkins.authorizationStrategy = rolesAndPermissions; - if (fineGrainAccessItems) { - jenkinsYaml.jenkins.authorizationStrategy.roleBased.roles.items = fineGrainAccessItems.map((item) => ({ + if (typeof fineGrainedAccessItems !== 'undefined') { + jenkinsYaml.jenkins.authorizationStrategy.roleBased.roles.items = fineGrainedAccessItems.map((item) => ({ entries: item.users.map((user) => ({ user })), name: item.roleName, pattern: item.pattern, - template: item.template, + templateName: item.templateName, })); } if (authType === 'github') { diff --git a/lib/compute/jenkins-main-node.ts b/lib/compute/jenkins-main-node.ts index 28dede72..2cd3874d 100644 --- a/lib/compute/jenkins-main-node.ts +++ b/lib/compute/jenkins-main-node.ts @@ -36,7 +36,7 @@ import { join } from 'path'; import { CloudwatchAgent } from '../constructs/cloudwatch-agent'; import { AgentNodeConfig, AgentNodeNetworkProps, AgentNodeProps } from './agent-node-config'; import { EnvConfig } from './env-config'; -import { AuthConfig, FineGrainAccessSpecs } from './auth-config'; +import { AuthConfig, FineGrainedAccessSpecs } from './auth-config'; import { ViewsConfig } from './views'; interface HttpConfigProps { @@ -51,7 +51,7 @@ interface LoginAuthProps { readonly authCredsSecretsArn: string; readonly authType: string; readonly adminUsers?: string[]; - readonly fineGrainAccessSpecs?: FineGrainAccessSpecs[]; + readonly fineGrainedAccessSpecs?: FineGrainedAccessSpecs[]; } interface DataRetentionProps { @@ -453,7 +453,8 @@ export class JenkinsMainNode { agentNodeObject: AgentNodeConfig, props: AgentNodeNetworkProps, agentNode: AgentNodeProps[], macAgent: string): string { let updatedConfig = agentNodeObject.addAgentConfigToJenkinsYaml(stack, agentNode, props, macAgent); if (loginAuthProps.authType !== 'default') { - updatedConfig = AuthConfig.addOidcConfigToJenkinsYaml(updatedConfig, loginAuthProps.authType, loginAuthProps.adminUsers); + updatedConfig = AuthConfig.addOidcConfigToJenkinsYaml(updatedConfig, loginAuthProps.authType, + loginAuthProps.adminUsers, loginAuthProps.fineGrainedAccessSpecs); } if (jenkinsMainNodeProps.envVarsFilePath !== '' && jenkinsMainNodeProps.envVarsFilePath != null) { updatedConfig = EnvConfig.addEnvConfigToJenkinsYaml(updatedConfig, jenkinsMainNodeProps.envVarsFilePath); diff --git a/test/compute/auth-config.test.ts b/test/compute/auth-config.test.ts index 02da54ec..5f4c4cc5 100644 --- a/test/compute/auth-config.test.ts +++ b/test/compute/auth-config.test.ts @@ -9,7 +9,7 @@ import { readFileSync } from 'fs'; import { load } from 'js-yaml'; import { JenkinsMainNode } from '../../lib/compute/jenkins-main-node'; -import { AuthConfig, FineGrainAccessSpecs } from '../../lib/compute/auth-config'; +import { AuthConfig, FineGrainedAccessSpecs } from '../../lib/compute/auth-config'; describe('Test authType OIDC', () => { // WHEN @@ -49,11 +49,11 @@ describe('Test authType github', () => { // WHEN const admins = ['foo', 'bar']; const yml: any = load(readFileSync(JenkinsMainNode.BASE_JENKINS_YAML_PATH, 'utf-8')); - const fineGrainedAccess: FineGrainAccessSpecs = { + const fineGrainedAccess: FineGrainedAccessSpecs = { users: ['user1', 'user2', 'user3'], roleName: 'builder-job-role', pattern: '((distribution|integ).*)', - template: 'builder-template', + templateName: 'builder-template', }; AuthConfig.addOidcConfigToJenkinsYaml(yml, 'github', admins, [fineGrainedAccess]); const globalRoles = yml.jenkins.authorizationStrategy.roleBased.roles.global; @@ -85,14 +85,14 @@ describe('Test authType github', () => { expect(adminUsers).toEqual(['admin', 'foo', 'bar']); }); - test('Verify read only', async () => { + test('Verify read only access', async () => { // Find the read role const readRole = globalRoles.find((role: any) => role.name === 'read'); expect(readRole).toBeTruthy(); // Check read users const readUsers = readRole.entries.map((entry: any) => entry.user); - expect(readUsers).toEqual(['anonymous']); + expect(readUsers).toEqual(['anonymous', 'authenticated']); }); test('Verify fine grained access', async () => {