Skip to content

Commit

Permalink
Dev build role2 (#441)
Browse files Browse the repository at this point in the history
* Add local dev build role 

Co-authored-by: Olaf Conijn <[email protected]>
  • Loading branch information
mhlchirosca and OlafConijn authored Jan 16, 2023
1 parent 2a29c92 commit cf1809f
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 7 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ All notable changes to aws organization formation will be documented in this fil
**BREAKING CHANGES**:
- v1.0.0: execution role under which org-formation is ran requires the ec2:describeRegions permission

**unreleased**
- feat: allow a development role to be configured on the OrganizationRoot (DefaultDevelopmentBuildAccessRoleName) which will be used when running using `--dev`

**version 1.0.6**
- fix: only prevent printing/ validating stacks if an account is added to organization.yml (not prevent printing if an OU got added)
- chore: better perf on update-organization task
Expand Down
2 changes: 1 addition & 1 deletion docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ Will perform tasks from *tasksFile*.
|<nobr>--failed-stacks-tolerance</nobr> | 0 | The number of failed stacks (within a task) after which execution stops|
|<nobr>--large-template-bucket-name</nobr> | 0 | The name of the S3 bucket that should be used when uploading templates larger than 50_000 bytes |
|<nobr>--match</nobr> | undefined | Matches a specific tasks using using a globPattern (e.g. `--match 'MyTask/**'`) or the exact name of a task.|

|<nobr>--dev</nobr> | false | use development settings, e.g. DefaultDevelopmentBuildAccessRoleName instead of DefaultBuildAccessRoleName |

Parameters can be passed using the following syntax:
``> org-formation perform-tasks taskfile.yml --parameters Param1=Val1 Param2=Val2``
Expand Down
1 change: 1 addition & 0 deletions docs/organization-resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ OrganizationRoot is the AWS Root Resource that functions like a top-level Organi
|DefaultOrganizationAccessRoleName| String | Default value for the OrganizationAccessRoleName attributes of accounts within the organization.<br/><br/>For more information see the [Account](#account) resources|
|DefaultBuildProcessAccessRoleName| String | Default value for the TaskRoleName of tasks, this value can be different from the DefaultOrganizationAccessRoleName value. OrganizationAccess is used to set up the account, BuildProcessAccess is used to deploy resources to these accounts.
|CloseAccountsOnRemoval| boolean | If set to true, [Account](#account) resources removed from `organization.yml` will be closed.
|DefaultDevelopmentBuildAccessRoleName| String | When configured, this value will be used instead of `DefaultBuildProcessAccessRoleName` when running using the `--dev` flag

**Note** Any account (or master account) within an AWS organization that is not part of an Organizational Unit will be a member of the Organizational Root.

Expand Down
5 changes: 3 additions & 2 deletions src/commands/base-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export abstract class BaseCliCommand<T extends ICommandArgs> {
}
}

public loadTemplatingContext(command: {templatingContextFile?: string; TemplatingContext?: {}}): void {
public loadTemplatingContext(command: { templatingContextFile?: string; TemplatingContext?: {} }): void {
if (typeof command.templatingContextFile === 'string') {
if (!existsSync(command.templatingContextFile)) {
throw new OrgFormationError('unable to find templating context file with path: ' + command.templatingContextFile);
Expand Down Expand Up @@ -302,7 +302,7 @@ export abstract class BaseCliCommand<T extends ICommandArgs> {
this.loadRuntimeConfiguration(command);

if (command.excludeAccounts) {
const exclude = !command.excludeAccounts ? [] : command.excludeAccounts.split(',').map(x=>x.trim());;
const exclude = !command.excludeAccounts ? [] : command.excludeAccounts.split(',').map(x => x.trim());;
ConsoleUtil.LogInfo(`excluding the following accounts: ${exclude.join(', ')}`);
AwsOrganizationReader.excludeAccountIds = exclude;
}
Expand Down Expand Up @@ -458,6 +458,7 @@ export interface ICommandArgs {
resolver?: CfnExpressionResolver;
partitionRegion?: string;
excludeAccounts?: string;
dev?: boolean;
}

export interface IRCObject {
Expand Down
5 changes: 5 additions & 0 deletions src/commands/perform-tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export class PerformTasksCommand extends BaseCliCommand<IPerformTasksCommandArgs
command.option('--templating-context-file [templating-context-file]', 'json file used as context for nunjuck text templating of organization and tasks file');
command.option('--match [match]', 'glob pattern used to define/filter which tasks to run.');
command.option('--large-template-bucket-name [large-template-bucket-name]', 'bucket used when uploading large templates. default is to create a bucket just-in-time in the target account');
command.option('--dev', 'use development settings, e.g. DefaultDevelopmentBuildAccessRoleName instead of DefaultBuildAccessRoleName', false);

command.option('--skip-storing-state', 'when set, the state will not be stored');
super.addOptions(command);
Expand All @@ -55,6 +56,10 @@ export class PerformTasksCommand extends BaseCliCommand<IPerformTasksCommandArgs
public async performCommand(command: IPerformTasksCommandArgs): Promise<void> {
const tasksFile = command.tasksFile;

if (command.dev) {
AwsUtil.SetIsDevelopmentBuild(true);
}

Validator.validatePositiveInteger(command.maxConcurrentStacks, 'maxConcurrentStacks');
Validator.validatePositiveInteger(command.failedStacksTolerance, 'failedStacksTolerance');
Validator.validatePositiveInteger(command.maxConcurrentTasks, 'maxConcurrentTasks');
Expand Down
10 changes: 8 additions & 2 deletions src/parser/model/account-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { IResource, IResourceRef, TemplateRoot } from '../parser';
import { PasswordPolicyResource } from './password-policy-resource';
import { Reference, Resource } from './resource';
import { ServiceControlPolicyResource } from './service-control-policy-resource';
import { DEFAULT_ROLE_FOR_CROSS_ACCOUNT_ACCESS } from '~util/aws-util';
import { AwsUtil, DEFAULT_ROLE_FOR_CROSS_ACCOUNT_ACCESS } from '~util/aws-util';
import { ConsoleUtil } from '~util/console-util';

export interface IAccountProperties {
RootEmail?: string;
Expand Down Expand Up @@ -108,7 +109,12 @@ export class AccountResource extends Resource {
}

if (this.buildAccessRoleName === undefined) {
this.buildAccessRoleName = this.root.organizationSection.organizationRoot?.defaultBuildAccessRoleName;
if (AwsUtil.IsDevelopmentBuild()) {
this.buildAccessRoleName = this.root.organizationSection.organizationRoot?.defaultDevelopmentBuildAccessRoleName;
this.buildAccessRoleName ?? ConsoleUtil.LogWarning('Development role is missing, falling back to the default behavior.');
} else {
this.buildAccessRoleName = this.root.organizationSection.organizationRoot?.defaultBuildAccessRoleName;
}
if (this.buildAccessRoleName === undefined) {
this.buildAccessRoleName = this.organizationAccessRoleName;
}
Expand Down
5 changes: 4 additions & 1 deletion src/parser/model/organization-root-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface IOrganizationRootProperties {
ServiceControlPolicies: IResourceRef | IResourceRef[];
DefaultOrganizationAccessRoleName?: string;
DefaultBuildAccessRoleName?: string;
DefaultDevelopmentBuildAccessRoleName?: string;
MirrorInPartition?: boolean;
CloseAccountsOnRemoval?: boolean;
}
Expand All @@ -16,6 +17,7 @@ export class OrganizationRootResource extends Resource {
private props: IOrganizationRootProperties;
public defaultOrganizationAccessRoleName?: string;
public defaultBuildAccessRoleName?: string;
public defaultDevelopmentBuildAccessRoleName?: string;
public mirrorInPartition?: boolean;
public closeAccountsOnRemoval?: boolean;

Expand All @@ -25,11 +27,12 @@ export class OrganizationRootResource extends Resource {
this.props = this.resource.Properties as IOrganizationRootProperties;

super.throwForUnknownAttributes(resource, id, 'Type', 'Properties');
super.throwForUnknownAttributes(this.props, id, 'ServiceControlPolicies', 'DefaultOrganizationAccessRoleName', 'DefaultBuildAccessRoleName', 'MirrorInPartition', 'CloseAccountsOnRemoval');
super.throwForUnknownAttributes(this.props, id, 'ServiceControlPolicies', 'DefaultOrganizationAccessRoleName', 'DefaultBuildAccessRoleName', 'DefaultDevelopmentBuildAccessRoleName', 'MirrorInPartition', 'CloseAccountsOnRemoval');

if (this.props) {
this.defaultOrganizationAccessRoleName = this.props.DefaultOrganizationAccessRoleName;
this.defaultBuildAccessRoleName = this.props.DefaultBuildAccessRoleName;
this.defaultDevelopmentBuildAccessRoleName = this.props.DefaultDevelopmentBuildAccessRoleName;
this.mirrorInPartition = this.props.MirrorInPartition;
this.closeAccountsOnRemoval = this.props.CloseAccountsOnRemoval;
}
Expand Down
11 changes: 10 additions & 1 deletion src/util/aws-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,14 @@ export class AwsUtil {
AwsUtil.isPartition = isPartition;
}

public static IsDevelopmentBuild(): boolean {
return AwsUtil.isDevelopmentBuild;
}

public static SetIsDevelopmentBuild(isDevelopmentBuild: boolean): void {
AwsUtil.isDevelopmentBuild = isDevelopmentBuild;
}

public static GetPartitionRegion(): string {
return AwsUtil.partitionRegion;
}
Expand Down Expand Up @@ -417,6 +425,7 @@ export class AwsUtil {
private static masterAccountId: string | PromiseLike<string>;
private static masterPartitionId: string | PromiseLike<string>;
private static partitionProfile: string | PromiseLike<string>;
private static isDevelopmentBuild = false;
private static largeTemplateBucketName: string | undefined;
private static partitionCredentials: CredentialsOptions;
private static buildProcessAccountId: string | PromiseLike<string>;
Expand Down Expand Up @@ -482,7 +491,7 @@ export class CfnUtil {
public static async UploadTemplateToS3IfTooLarge(stackInput: CreateStackInput | UpdateStackInput | ValidateTemplateInput, binding: ICfnBinding, stackName: string, templateHash: string): Promise<void> {
if (stackInput.TemplateBody && stackInput.TemplateBody.length > 50000) {
const s3Service = await AwsUtil.GetS3Service(binding.accountId, binding.region, binding.customRoleName);
const preExistingBucket = AwsUtil.GetLargeTemplateBucketName() ;
const preExistingBucket = AwsUtil.GetLargeTemplateBucketName();
const bucketName = preExistingBucket ?? `org-formation-${binding.accountId}-${binding.region}-large-templates`;
if (!preExistingBucket) {
try {
Expand Down

0 comments on commit cf1809f

Please sign in to comment.