Skip to content

Commit

Permalink
Support fine grain access control
Browse files Browse the repository at this point in the history
Signed-off-by: Sayali Gaikawad <gaiksaya@amazon.com>
  • Loading branch information
gaiksaya committed Dec 5, 2024
1 parent 29245f3 commit 43f7404
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 955 deletions.
21 changes: 20 additions & 1 deletion bin/ci-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,39 @@
*/

import { App } from 'aws-cdk-lib';
import { Peer } from 'aws-cdk-lib/aws-ec2';
import { CiCdnStack } from '../lib/ci-cdn-stack';
import { CIConfigStack } from '../lib/ci-config-stack';
import { CIStack } from '../lib/ci-stack';

const app = new App();

const defaultEnv: string = 'Dev';
const defaultEnv: string = 'lol';

const ciConfigStack = new CIConfigStack(app, `OpenSearch-CI-Config-${defaultEnv}`, {});

const ciStack = new CIStack(app, `OpenSearch-CI-${defaultEnv}`, {
env: {
region: process.env.CDK_DEFAULT_REGION,
},
useSsl: true,
adminUsers: ['gaiksaya'],
authType: 'github',
fineGrainAccessSpecs: [
{
users: ['gaiksaya', 'sayaligaikawad'],
roleName: 'temp-role',
pattern: '.*',
template: 'builder-template',
},
{
users: ['foo', 'bar'],
roleName: 'temp-role-2',
pattern: '(?)integ*',
template: 'builder-template',
},
],
restrictServerAccessTo: Peer.prefixList('pl-f8a64391'),
});

const ciCdnStack = new CiCdnStack(app, `OpenSearch-CI-Cdn-${defaultEnv}`, {});
Expand Down
32 changes: 18 additions & 14 deletions lib/ci-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,35 @@ 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';

export interface CIStackProps extends StackProps {
/** Should the Jenkins use https */
readonly useSsl?: boolean;
/** Type of login mechanism to adopt */
readonly authType?: string;
/** Restrict jenkins access to */
readonly restrictServerAccessTo?: IPeer;
/** Additional verification during deployment and resource startup. */
readonly ignoreResourcesFailures?: boolean;
/** Users with admin access during initial deployment */
readonly adminUsers?: string[];
/** Additional logic that needs to be run on Master Node. The value has to be path to a file */
readonly additionalCommands?: string;
/** Do you want to retain jenkins jobs and build history */
readonly dataRetention?: boolean;
/** Users with admin access during initial deployment */
readonly adminUsers?: string[];
/** IAM role ARN to be assumed by jenkins agent nodes eg: cross-account */
readonly agentAssumeRole?: string[];
/** Type of login mechanism to adopt */
readonly authType?: string;
/** Fine grain access control specifications */
readonly fineGrainAccessSpecs?: FineGrainAccessSpecs[];
/** Do you want to retain jenkins jobs and build history */
readonly dataRetention?: boolean;
/** Enable views on jenkins UI */
readonly enableViews?: boolean;
/** File path containing global environment variables to be added to jenkins enviornment */
readonly envVarsFilePath?: string;
/** Additional verification during deployment and resource startup. */
readonly ignoreResourcesFailures?: boolean;
/** Add Mac agent to jenkins */
readonly macAgent?: boolean;
/** Enable views on jenkins UI */
readonly enableViews?: boolean;
/** Restrict jenkins access to */
readonly restrictServerAccessTo?: IPeer;
/** Use Production Agents */
readonly useProdAgents?: boolean;
/** Should the Jenkins use https */
readonly useSsl?: boolean;
}

function getServerAccess(serverAccessType: string, restrictServerAccessTo: string): IPeer {
Expand Down Expand Up @@ -190,6 +193,7 @@ export class CIStack extends Stack {
authCredsSecretsArn: importedAuthConfigValuesSecretBucketValue.toString(),
useSsl,
authType,
fineGrainAccessSpecs: props?.fineGrainAccessSpecs,
failOnCloudInitError: props?.ignoreResourcesFailures,
adminUsers: props?.adminUsers,
agentNodeSecurityGroup: this.securityGroups.agentNodeSG.securityGroupId,
Expand Down
36 changes: 33 additions & 3 deletions lib/compute/auth-config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { dump } from 'js-yaml';
import { writeFileSync } from 'fs';

/**
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
export interface FineGrainAccessSpecs {
users: string[],
roleName: string,
pattern: string,
template: string
}

export class AuthConfig {
private static readonly adminRolePermissions: string[] = [
Expand Down Expand Up @@ -50,7 +59,18 @@ export class AuthConfig {
'View/Read',
];

public static addOidcConfigToJenkinsYaml(yamlObject: any, authType: string, admins?: string[]): any {
private static readonly builderTemplatePermissions: string[] = [
'Job/Build',
'Job/Cancel',
'Job/Discover',
'Job/Read',
'Lockable Resources/View',
'Run/Replay',
'Metrics/View',
'View/Read',
];

public static addOidcConfigToJenkinsYaml(yamlObject: any, authType: string, admins?: string[], fineGrainAccessItems?: FineGrainAccessSpecs[]): any {
const jenkinsYaml: any = yamlObject;
let adminUsers: string[] = ['admin'];
const readOnlyUsers: string[] = ['anonymous'];
Expand Down Expand Up @@ -89,6 +109,10 @@ export class AuthConfig {

const rolesAndPermissions: { [x: string]: any; } = {
roleBased: {
permissionTemplates: {
name: 'builder-template',
permissions: AuthConfig.builderTemplatePermissions,
},
roles: {
global: [{
entries: adminUsers.map((user) => ({ user })),
Expand All @@ -103,14 +127,20 @@ export class AuthConfig {
pattern: '.*',
permissions: AuthConfig.readOnlyRolePermissions,
},

],
},
},
};

jenkinsYaml.jenkins.authorizationStrategy = rolesAndPermissions;

if (fineGrainAccessItems) {
jenkinsYaml.jenkins.authorizationStrategy.roleBased.roles.items = fineGrainAccessItems.map((item) => ({
entries: item.users.map((user) => ({ user })),
name: item.roleName,
pattern: item.pattern,
template: item.template,
}));
}
if (authType === 'github') {
jenkinsYaml.jenkins.securityRealm = githubAuthConfig;
} else {
Expand Down
3 changes: 2 additions & 1 deletion lib/compute/jenkins-main-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 } from './auth-config';
import { AuthConfig, FineGrainAccessSpecs } from './auth-config';
import { ViewsConfig } from './views';

interface HttpConfigProps {
Expand All @@ -51,6 +51,7 @@ interface LoginAuthProps {
readonly authCredsSecretsArn: string;
readonly authType: string;
readonly adminUsers?: string[];
readonly fineGrainAccessSpecs?: FineGrainAccessSpecs[];
}

interface DataRetentionProps {
Expand Down
24 changes: 12 additions & 12 deletions test/ci-stack.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { CIStack } from '../lib/ci-stack';
test('CI Stack Basic Resources', () => {
const app = new App({
context: {
useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', additionalCommands: './test/data/hello-world.py',
useSsl: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', additionalCommands: './test/data/hello-world.py',
},
});

Expand Down Expand Up @@ -45,7 +45,7 @@ test('CI Stack Basic Resources', () => {
test('External security group is open', () => {
const app = new App({
context: {
useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: 'all',
useSsl: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: 'all',
},
});

Expand Down Expand Up @@ -89,7 +89,7 @@ test('External security group is open', () => {
test('External security group is restricted', () => {
const app = new App({
context: {
useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.0.0.0/24',
useSsl: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.0.0.0/24',
},
});

Expand Down Expand Up @@ -135,7 +135,7 @@ test('External security group is restricted', () => {
test('MainNode', () => {
const app = new App({
context: {
useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32',
useSsl: 'true', authType: 'oidc', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32',
},
});

Expand Down Expand Up @@ -167,7 +167,7 @@ test('MainNode', () => {
test('LoadBalancer', () => {
const app = new App({
context: {
useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: 'all',
useSsl: 'true', authType: 'oidc', serverAccessType: 'ipv4', restrictServerAccessTo: 'all',
},
});

Expand All @@ -192,7 +192,7 @@ test('LoadBalancer', () => {
test('CloudwatchCpuAlarm', () => {
const app = new App({
context: {
useSsl: 'false', runWithOidc: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32',
useSsl: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32',
},
});

Expand All @@ -211,7 +211,7 @@ test('CloudwatchCpuAlarm', () => {
test('CloudwatchMemoryAlarm', () => {
const app = new App({
context: {
useSsl: 'false', runWithOidc: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32',
useSsl: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32',
},
});

Expand All @@ -230,7 +230,7 @@ test('CloudwatchMemoryAlarm', () => {
test('LoadBalancer Access Logging', () => {
const app = new App({
context: {
useSsl: 'false', runWithOidc: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32',
useSsl: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32',
},
});

Expand Down Expand Up @@ -367,7 +367,7 @@ test('LoadBalancer Access Logging', () => {
test('WAF rules', () => {
const app = new App({
context: {
useSsl: 'false', runWithOidc: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '0.0.0.0/0',
useSsl: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '0.0.0.0/0',
},
});

Expand Down Expand Up @@ -452,7 +452,7 @@ test('WAF rules', () => {
test('Test WAF association with ALB', () => {
const app = new App({
context: {
useSsl: 'false', runWithOidc: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '0.0.0.0/0',
useSsl: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '0.0.0.0/0',
},
});

Expand All @@ -478,7 +478,7 @@ test('Test WAF association with ALB', () => {
test('Test configElement jenkins content to use X-Forwarded-For header on port 443', () => {
const app = new App({
context: {
useSsl: 'true', runWithOidc: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '0.0.0.0/0',
useSsl: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '0.0.0.0/0',
},
});

Expand Down Expand Up @@ -512,7 +512,7 @@ test('Test configElement jenkins content to use X-Forwarded-For header on port 4
test('Test configElement jenkins content to use X-Forwarded-For header on port 80', () => {
const app = new App({
context: {
useSsl: 'false', runWithOidc: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '0.0.0.0/0',
useSsl: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '0.0.0.0/0',
},
});

Expand Down
Loading

0 comments on commit 43f7404

Please sign in to comment.