├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── container.yaml │ └── integration-test.yml ├── .gitignore ├── .npmrc ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── _config.yml ├── cli-program.ts ├── cli.ts ├── docs ├── 0.9.15-permission-change.md ├── access-denied.md ├── articles │ ├── aws-organizations.md │ ├── aws-organizations │ │ ├── cross-account-resource.png │ │ ├── cross-account-service.png │ │ ├── dev-prod-accounts.png │ │ └── organization.png │ └── org-formation.md ├── cli-reference.md ├── cloudformation-resources.md ├── diagrams │ ├── CIS benchmark.png │ ├── breakglass role.png │ ├── budgets.png │ ├── guardduty.png │ └── src │ │ ├── AccountCreation.drawio │ │ ├── CIS benchmark.drawio │ │ ├── breakglass role.drawio │ │ ├── budgets basic.drawio │ │ ├── budgets.drawio │ │ ├── cloudtrail.drawio │ │ ├── cross account bucket │ │ ├── cross account lambda │ │ ├── cross account role │ │ ├── cross account secret.drawio │ │ ├── guardduty basic.drawio │ │ ├── guardduty.drawio │ │ ├── organization.drawio │ │ ├── subdomains.drawio │ │ └── wildcard-certs ├── features.pdf ├── img │ ├── chainslayer.png │ ├── feature-1-update-org.png │ ├── feature-2-update-stacks.png │ ├── feature-3-perform-tasks.png │ ├── govcloud-org-formation-init.png │ ├── govcloud-org-formation-perform-tasks.png │ ├── govcloud-org-formation-update.png │ ├── moneyou.svg │ ├── org-formation-init.png │ └── stedi.png ├── least-priviledge.md ├── organization-resources.md ├── organizationAccountAccessRole.yml ├── task-files.md └── us-govcloud-partition.md ├── examples ├── automation │ └── create-account │ │ ├── .gitignore │ │ ├── handler.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── readme.md │ │ └── serverless.yml ├── eventbus │ ├── central-bus.yml │ └── organization-tasks.yml ├── img │ ├── account-creation.png │ ├── budget-alarms.png │ ├── cloudtrail.png │ ├── cross-account-bucket.png │ ├── cross-account-lambda.png │ ├── cross-account-role-with-alarm.png │ ├── cross-account-role.png │ ├── cross-account-secret.png │ ├── guardduty.png │ ├── organization.png │ ├── subdomains.png │ ├── terraform.png │ └── wildcard-certs.png ├── lambda-using-read-file │ ├── lambda-using-read-file.yml │ ├── organization-tasks.yml │ ├── organization.yml │ └── src │ │ └── index.js ├── lambda-using-uploaded-zip │ ├── lambda-template-using-zip.yml │ ├── org-formation-deployment-bucket.yml │ ├── organization-tasks.yml │ ├── organization.yml │ └── src │ │ ├── index.js │ │ ├── logger.js │ │ ├── package.json │ │ └── run-local.js ├── organization-iam-tasks.yml ├── organization-tasks.yml ├── organization.yml ├── readme.md ├── secure-defaults │ ├── organization-tasks.yml │ ├── register-type-tasks.yml │ └── secure-defaults-template.yml ├── security-hub │ ├── organization-tasks.yml │ ├── register-type-tasks.yml │ ├── security-hub.png │ └── templates │ │ ├── aws-config.yml │ │ ├── secure-defaults.yml │ │ ├── security-hub-controls.yml │ │ ├── security-hub-insights.yml │ │ └── security-hub.yml ├── service-quotas │ ├── organization-tasks.yml │ ├── register-type-tasks.yml │ └── service-quotas-template.yml ├── sso │ ├── img │ │ ├── sso.drawio │ │ └── sso.png │ ├── organization-tasks.yml │ ├── organization.yml │ ├── readme.md │ └── templates │ │ ├── generic-sns.yml │ │ ├── sso-custom-policies.yml │ │ ├── sso-generic-role.yml │ │ └── sso-identity-provider.yml ├── templates │ ├── budget-alarms.yml │ ├── cloudfront-s3.yml │ ├── cloudtrail.yml │ ├── cross-account-bucket.yml │ ├── cross-account-lambda.yml │ ├── cross-account-role-with-alarm.yml │ ├── cross-account-role.yml │ ├── cross-account-secret.yml │ ├── guardduty.yml │ ├── subdomains.yml │ └── wildcard-certs.yml ├── templating │ ├── organization-tasks.yaml │ └── security-group.njk └── terraform │ ├── bucket │ └── main.tf │ ├── organization-tasks.yml │ ├── organization.yml │ └── s3-state-bucket.yml ├── jest.config.js ├── not-supported.md ├── package-lock.json ├── package.json ├── resources ├── buildspec.yml ├── delegated-build-orgformation-tasks.yml ├── initial-commit │ ├── .org-formationrc │ └── organization-tasks.yml ├── local-build-orgformation-tasks.yml ├── organization-parameters.yml ├── orgformation-build-access-role.yml └── orgformation-codepipeline.yml ├── src ├── aws-provider │ ├── aws-account-access.ts │ ├── aws-events.ts │ ├── aws-organization-reader.ts │ ├── aws-organization-writer.ts │ ├── aws-organization.ts │ └── util.ts ├── build-tasks │ ├── build-configuration.ts │ ├── build-runner.ts │ ├── build-task-provider.ts │ └── tasks │ │ ├── annotate-organization-task.ts │ │ ├── annotate-organization.ts │ │ ├── include-task.ts │ │ ├── update-organization-task.ts │ │ └── update-stacks-task.ts ├── cfn-binder │ ├── cfn-binder.ts │ ├── cfn-parameters.ts │ ├── cfn-sub-expression.ts │ ├── cfn-task-provider.ts │ ├── cfn-task-runner.ts │ ├── cfn-template.ts │ └── cfn-validate-task-provider.ts ├── change-set │ └── change-set-provider.ts ├── commands │ ├── base-command.ts │ ├── create-organization-changeset.ts │ ├── delete-stacks.ts │ ├── describe-stacks.ts │ ├── execute-organization-changeset.ts │ ├── index.ts │ ├── init-organization-pipeline.ts │ ├── init-organization.ts │ ├── perform-tasks.ts │ ├── print-changeset.ts │ ├── print-org.ts │ ├── print-stacks.ts │ ├── print-tasks.ts │ ├── remove.ts │ ├── update-organization.ts │ ├── update-stacks.ts │ ├── validate-organization.ts │ ├── validate-stacks.ts │ └── validate-tasks.ts ├── core │ ├── cfn-expression-resolver.ts │ ├── cfn-expression.ts │ ├── cfn-functions │ │ ├── cfn-cmd.ts │ │ ├── cfn-find-in-map.ts │ │ ├── cfn-functions.ts │ │ ├── cfn-join.ts │ │ ├── cfn-json-string.ts │ │ ├── cfn-md5.ts │ │ ├── cfn-merge.ts │ │ ├── cfn-read-file.ts │ │ ├── cfn-select.ts │ │ └── cfn-sub.ts │ ├── cfn-parameters.ts │ ├── default-task-runner.ts │ └── generic-task-runner.ts ├── org-binder │ ├── org-binder.ts │ ├── org-task-runner.ts │ └── org-tasks-provider.ts ├── org-formation-error.ts ├── parser │ ├── model │ │ ├── account-resource.ts │ │ ├── cloudformation-resource.ts │ │ ├── index.ts │ │ ├── master-account-resource.ts │ │ ├── organization-bindings-section.ts │ │ ├── organization-root-resource.ts │ │ ├── organization-section.ts │ │ ├── organizational-unit-resource.ts │ │ ├── password-policy-resource.ts │ │ ├── resource-types.ts │ │ ├── resource.ts │ │ ├── resources-section.ts │ │ └── service-control-policy-resource.ts │ ├── parser.ts │ └── validator.ts ├── plugin │ ├── impl │ │ ├── cdk-build-task-plugin.ts │ │ ├── rp-build-task-plugin.ts │ │ ├── s3-copy-build-task-plugin.ts │ │ ├── sls-build-task-plugin.ts │ │ └── tf-apply-task-plugin.ts │ ├── plugin-binder.ts │ ├── plugin-command.ts │ ├── plugin-task.ts │ ├── plugin-util.ts │ └── plugin.ts ├── state │ ├── persisted-state.ts │ └── storage-provider.ts ├── util │ ├── aws-config.ts │ ├── aws-types.ts │ ├── aws-util.ts │ ├── child-process-util.ts │ ├── console-util.ts │ ├── credentials-provider-custom-env.ts │ ├── credentials-provider-partition.ts │ ├── file-util.ts │ ├── global-state.ts │ ├── initial-commit-util.ts │ ├── md5-util.ts │ └── resource-util.ts ├── writer │ └── default-template-writer.ts └── yaml-cfn │ ├── LICENSE │ ├── index.ts │ ├── nunjucks-parse-includes.ts │ └── yaml-parse-includes.ts ├── test ├── integration-tests │ ├── base-integration-test.ts │ ├── cdk-task.test.ts │ ├── cdk-upgrade-from-0.9.4.test.ts │ ├── cli-tests │ │ ├── cli-version.test.ts │ │ └── failed-tasks.test.ts │ ├── create-buckets.test.ts │ ├── init.test.ts │ ├── move-master-acc.test.ts │ ├── nested-ou-duplicate-names.test.ts │ ├── nested-ou-three-levels-deep.test.ts │ ├── nested-ou.test.ts │ ├── resources │ │ ├── scenario-anchors-aliases │ │ │ ├── 1-deploy.yml │ │ │ ├── 9-cleanup.yml │ │ │ ├── buckets.yml │ │ │ └── organization.yml │ │ ├── scenario-annotate-organization │ │ │ ├── 1-deploy.yml │ │ │ ├── buckets.yml │ │ │ └── organization.yml │ │ ├── scenario-attach-account │ │ │ ├── 1-init-organization.yml │ │ │ ├── 2-attach-organization.yml │ │ │ ├── 3-detach-organization.yml │ │ │ └── state.json │ │ ├── scenario-cdk-no-region │ │ │ ├── 1-deploy-cdk-workload-1target.yml │ │ │ ├── organization.yml │ │ │ ├── state.json │ │ │ └── workload │ │ │ │ ├── cdk.json │ │ │ │ ├── index.ts │ │ │ │ ├── package.json │ │ │ │ └── tsconfig.json │ │ ├── scenario-cdk-task │ │ │ ├── 1-deploy-cdk-workload-2targets.yml │ │ │ ├── 2-update-cdk-workload-with-parameters.yml │ │ │ ├── 3-deploy-cdk-workload-1target.yml │ │ │ ├── 4-remove-cdk-workload-task.yml │ │ │ ├── organization.yml │ │ │ ├── state.json │ │ │ └── workload │ │ │ │ ├── cdk.json │ │ │ │ ├── cdk.out │ │ │ │ ├── MyStack.template.json │ │ │ │ ├── cdk.out │ │ │ │ ├── manifest.json │ │ │ │ └── tree.json │ │ │ │ ├── index.d.ts │ │ │ │ ├── index.js │ │ │ │ ├── index.ts │ │ │ │ ├── package.json │ │ │ │ └── tsconfig.json │ │ ├── scenario-cfn-parameter-expressions │ │ │ ├── 1-deploy-update-stacks-with-param-expressions.yml │ │ │ ├── 2-cleanup-update-stacks-with-param-expressions.yml │ │ │ ├── bucket-policy.yml │ │ │ ├── bucket.yml │ │ │ ├── file.txt │ │ │ ├── organization.yml │ │ │ └── test.json │ │ ├── scenario-cleanup-stacks │ │ │ ├── organization-tasks-buckets.yml │ │ │ ├── organization-tasks-empty.yml │ │ │ ├── organization.yml │ │ │ ├── state.json │ │ │ └── templates │ │ │ │ ├── buckets.yml │ │ │ │ └── custom-role.yml │ │ ├── scenario-copy-to-s3 │ │ │ ├── 1-copy-to-s3.yml │ │ │ ├── files │ │ │ │ ├── file.txt │ │ │ │ ├── something-else.txt │ │ │ │ └── template.njk │ │ │ ├── organization.yml │ │ │ └── template-fixed-export.yml │ │ ├── scenario-copyvalue-buildrole │ │ │ ├── 0-tasks.yml │ │ │ ├── 9-cleanup-organization.yml │ │ │ ├── bucket.yml │ │ │ ├── bucket2.yml │ │ │ └── organization.yml │ │ ├── scenario-create-account │ │ │ ├── 0-update-organization.yml │ │ │ ├── 1-update-organization.yml │ │ │ ├── 9-cleanup-organization.yml │ │ │ ├── organization-2.yml │ │ │ └── organization.yml │ │ ├── scenario-create-buckets │ │ │ ├── buckets.yml │ │ │ └── organization.yml │ │ ├── scenario-delegated-build-account │ │ │ ├── 0-update-organization.yml │ │ │ ├── 1-update-organization.yml │ │ │ ├── 9-cleanup-organization.yml │ │ │ ├── bucket.yml │ │ │ ├── build-role.yml │ │ │ ├── organization-2.yml │ │ │ └── organization.yml │ │ ├── scenario-detached-perform-tasks │ │ │ ├── 0-tasks.yml │ │ │ ├── 9-cleanup.yml │ │ │ ├── bucket.yml │ │ │ ├── build-role.yml │ │ │ ├── organization.yml │ │ │ └── state.json │ │ ├── scenario-functions-in-cfn │ │ │ ├── 1-deploy-cfn-with-functions.yml │ │ │ ├── 9-cleanup-cfn-with-functions.yml │ │ │ ├── bucket-with-policy1.yml │ │ │ ├── bucket-with-policy2.yml │ │ │ ├── bucketPolicyDoc.json │ │ │ ├── lambda-using-read-file-code.js │ │ │ ├── lambda-using-read-file.yml │ │ │ └── organization.yml │ │ ├── scenario-global-params │ │ │ ├── 0-include.yml │ │ │ ├── 1-spread-operator.yml │ │ │ ├── bucket.yml │ │ │ ├── global-parameters.yml │ │ │ ├── included.yml │ │ │ └── organization.yml │ │ ├── scenario-include-file-twice │ │ │ ├── 0-organization-tasks-1include.yml │ │ │ ├── 0-organization-tasks.yml │ │ │ ├── 1-organization-tasks-missing-param.yml │ │ │ ├── included-task-file.yml │ │ │ ├── organization.yml │ │ │ └── resources │ │ │ │ ├── bucket.yml │ │ │ │ └── file.txt │ │ ├── scenario-include-various │ │ │ ├── 1-deploy.yml │ │ │ ├── 9-cleanup.yml │ │ │ ├── includes │ │ │ │ ├── account-a.yml │ │ │ │ ├── lambda.js │ │ │ │ ├── lambda.yml │ │ │ │ └── tags.yml │ │ │ ├── lambda.yml │ │ │ └── organization.yml │ │ ├── scenario-included-update-org │ │ │ ├── buckets.yml │ │ │ ├── include-with-tasks.yml │ │ │ ├── include-with-update.yml │ │ │ ├── organization.yml │ │ │ └── toplevel-tasks.yml │ │ ├── scenario-json-template │ │ │ ├── 1-deploy-json-stack.yml │ │ │ ├── 9-cleanup-json-stack.yml │ │ │ ├── buckets.json │ │ │ └── organization.yml │ │ ├── scenario-move-master-acc │ │ │ ├── 1-init-organization.yml │ │ │ ├── 2-move-to-ou-organization.yml │ │ │ ├── 3-move-to-other-ou-organization.yml │ │ │ ├── 4-back-to-org-root-organization.yml │ │ │ └── state.json │ │ ├── scenario-nested-ou │ │ │ ├── 0-state.json │ │ │ ├── 1-init-organization.yml │ │ │ ├── 2-create-parent-child-ou.yml │ │ │ ├── 3-swap-child-parent-ou.yml │ │ │ ├── 4-delete-parent-keep-child.yml │ │ │ ├── 5-three-levels-deep.yml │ │ │ ├── 6-duplicate-names.yml │ │ │ └── 7-cleanup-organization.yml │ │ ├── scenario-new-account │ │ │ ├── buckets.yml │ │ │ ├── organization.yml │ │ │ └── task.yml │ │ ├── scenario-no-bucket │ │ │ ├── 1-deploy-no-bucket.yml │ │ │ ├── my-role.yml │ │ │ └── organization.yml │ │ ├── scenario-non-local-templates │ │ │ ├── 0-tasks.yml │ │ │ ├── 9-cleanup-tasks.yml │ │ │ ├── buckets.yml │ │ │ └── organization.yml │ │ ├── scenario-organization-file-s3 │ │ │ ├── organization.yml │ │ │ └── task.yml │ │ ├── scenario-perform-tasks │ │ │ ├── 0-tasks.yml │ │ │ └── organization.yml │ │ ├── scenario-register-type │ │ │ ├── 1-register-type.yml │ │ │ ├── 2-register-type-changed-org.yml │ │ │ ├── 3-register-type-added-account.yml │ │ │ ├── 4-move-register-type-to-include.yml │ │ │ ├── 9-cleanup.yml │ │ │ ├── include-with-type.yml │ │ │ ├── organization-2.yml │ │ │ ├── organization-3.yml │ │ │ └── organization.yml │ │ ├── scenario-serverless-com-task │ │ │ ├── 1-deploy-serverless-workload-2targets.yml │ │ │ ├── 2-update-serverless-workload-with-parameters.yml │ │ │ ├── 3-deploy-serverless-workload-1target.yml │ │ │ ├── 4-remove-serverless-workload-task.yml │ │ │ ├── organization.yml │ │ │ └── workload │ │ │ │ ├── .gitignore │ │ │ │ ├── handler.js │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ └── serverless.yml │ │ ├── scenario-skip-tasks │ │ │ ├── included.yml │ │ │ ├── organization.yml │ │ │ └── skip-tasks.yml │ │ ├── scenario-task-file-parameters │ │ │ ├── 1-task-file-with-parameters.yml │ │ │ ├── bucket.yml │ │ │ ├── included-task-file-with-pseudo-param.yml │ │ │ ├── included-task-file.yml │ │ │ └── organization.yml │ │ ├── scenario-task-that-fails │ │ │ ├── invalid-template.yml │ │ │ ├── organization-tasks.yml │ │ │ └── organization.yml │ │ ├── scenario-text-template-all │ │ │ ├── 1-deploy-text-templated-things.yml │ │ │ ├── 9-cleanup-text-templated-things.yml │ │ │ ├── buckets.yml │ │ │ ├── included-task.njk │ │ │ ├── organization.njk │ │ │ └── templating-context.json │ │ ├── scenario-text-template-mixed │ │ │ ├── 1-deploy.yml │ │ │ ├── 9-cleanup.yml │ │ │ ├── buckets.yml │ │ │ ├── included-task.njk │ │ │ ├── organization.yml │ │ │ └── teams.json │ │ ├── scenario-text-templating │ │ │ ├── nunjucks-template-included.njk │ │ │ ├── nunjucks-template-with-include.njk │ │ │ ├── nunjucks-template.njk │ │ │ ├── organization-tasks.yml │ │ │ └── organization.yml │ │ ├── scenario-tf-task │ │ │ ├── 1-deploy-tf-workload.yml │ │ │ ├── 2-remove-tf-workload.yml │ │ │ ├── folder-with-terraform │ │ │ │ └── main.tf │ │ │ ├── organization.yml │ │ │ └── state.json │ │ ├── scenario-update-stacks-custom-role │ │ │ ├── 1-deploy-stacks-custom-roles.yml │ │ │ ├── 2-cleanup-stacks-custom-roles.yml │ │ │ ├── buckets.yml │ │ │ ├── my-roles.yml │ │ │ └── organization.yml │ │ ├── scenario-update-stacks-stack-policy │ │ │ ├── 1-deploy-stacks-with-stack-policy.yml │ │ │ ├── 2-update-stacks-with-stack-policy.yml │ │ │ ├── 3-update-stack-policy.yml │ │ │ ├── 4-update-stack-policy-using-flag.yml │ │ │ ├── 5-update-stack-policy-using-flag-false.yml │ │ │ ├── 6-update-stack-policy-clearing-policy.yml │ │ │ ├── 9-cleanup-stacks-with-stack-policy.yml │ │ │ ├── buckets-update.yml │ │ │ ├── buckets.yml │ │ │ └── organization.yml │ │ ├── scenario-update-stacks-tags │ │ │ ├── 1-deploy-stacks-with-tags.yml │ │ │ ├── 2-deploy-stacks-without-tags.yml │ │ │ ├── 9-cleanup-stacks-with-tags.yml │ │ │ ├── buckets.yml │ │ │ └── organization.yml │ │ ├── scenario-very-large-stack │ │ │ ├── 1-deploy-very-large-stack.yml │ │ │ ├── 9-cleanup-very-large-stack.yml │ │ │ ├── buckets.yml │ │ │ └── organization.yml │ │ └── state.json │ ├── scenario-anchors-aliases.test.ts │ ├── scenario-annotate-organization.test.ts │ ├── scenario-attach-account.test.ts │ ├── scenario-cleanup-stacks.test.ts │ ├── scenario-copy-to-s3-task.test.ts │ ├── scenario-copyvalue-buildrole.test.ts │ ├── scenario-create-account.test.ts │ ├── scenario-delegated-build-account.test.ts │ ├── scenario-detached-perform-tasks.test.ts │ ├── scenario-functions-in-cfn.test.ts │ ├── scenario-global-params.test.ts │ ├── scenario-include-file-twice.test.ts │ ├── scenario-include-various.test.ts │ ├── scenario-included-update-org.test.ts │ ├── scenario-json-stack.test.ts │ ├── scenario-new-account.test.ts │ ├── scenario-no-bucket.test.ts │ ├── scenario-non-local-templates.test.ts │ ├── scenario-organization-file-s3.test.ts │ ├── scenario-perform-tasks.test.ts │ ├── scenario-register-type.test.ts │ ├── scenario-serverless-com-task.test.ts │ ├── scenario-skip-tasks.test.ts │ ├── scenario-task-file-parameters.test.ts │ ├── scenario-task-that-fails.test.ts │ ├── scenario-text-template-all.test.ts │ ├── scenario-text-template-mixed.test.ts │ ├── scenario-text-templating.test.ts │ ├── scenario-tf-task.test.ts │ ├── scenario-update-stacks-custom-role.test.ts │ ├── scenario-update-stacks-stack-policy.test.ts │ ├── scenario-update-stacks-stack-tags.test.ts │ ├── scenario-update-stacks-with-param-expressions.test.ts │ ├── scenario-very-large-stack.test.ts │ ├── temp │ │ └── .keep │ └── tools │ │ ├── delete-buckets.ts │ │ └── test-cfn-exports-backoff.ts ├── resources │ ├── budget-alarms │ │ ├── budget-alarms.yml │ │ └── organization.yml │ ├── cloudformation-template-params.yml │ ├── cloudformation-template.yml │ ├── cloudtrail │ │ ├── cloudtrail.yml │ │ └── organization.yml │ ├── conditionals │ │ ├── conditionals.yml │ │ └── organization.yml │ ├── custom-parameter-binding │ │ ├── custom-parameter-binding-non-existant.yml │ │ ├── custom-parameter-binding.yml │ │ └── organization.yml │ ├── defaults │ │ ├── default-binding.yml │ │ ├── default-organization-bindings.yml │ │ ├── default-regions.yml │ │ └── organization.yml │ ├── depends-on-account │ │ ├── depends-on-account-multiple.yml │ │ ├── depends-on-account.yml │ │ ├── depends-on-master-account.yml │ │ ├── depends-on-unknown-account.yml │ │ └── organization.yml │ ├── depends-on │ │ ├── depends-on.yml │ │ └── organization.yml │ ├── empty-file.yml │ ├── enum-expressions │ │ ├── enum-expressions.yml │ │ └── organization.yml │ ├── foreach │ │ ├── foreach.yml │ │ └── organization.yml │ ├── hostedzone-per-account │ │ ├── hostedzone-per-account.yml │ │ └── organization.yml │ ├── invalid-include-invalid-yml.yml │ ├── invalid-include-notfound.yml │ ├── invalid-version.yml │ ├── invalid-yml.yml │ ├── merge-include1.yml │ ├── merge-include2.yml │ ├── merge-include3.yml │ ├── merge.yml │ ├── missing-organization.yml │ ├── missing-version.yml │ ├── organization-binding │ │ ├── organization-binding-account-id.yml │ │ ├── organization-binding-through-param.yml │ │ └── organization.yml │ ├── organization-bindings-section │ │ ├── organization-bindings-section.yml │ │ └── organization.yml │ ├── references │ │ ├── organization.yml │ │ ├── reference-to-account-in-param.yml │ │ ├── reference-to-multiple.yml │ │ └── reference-using-sub.yml │ ├── tasks │ │ ├── build-tasks-duplicate-stackname.yml │ │ ├── build-tasks-empty.yml │ │ ├── build-tasks-include-empty.yml │ │ ├── build-tasks-include-with-duplicate-nested.yml │ │ ├── build-tasks-include-with-duplicate.yml │ │ ├── build-tasks-include-with-update-org.yml │ │ ├── build-tasks-param-account-ref.yml │ │ ├── build-tasks.yml │ │ ├── include-include1.yml │ │ ├── include1.yml │ │ ├── include2.yml │ │ ├── organization.yml │ │ ├── task-depends-on-non-existing.yml │ │ └── templates │ │ │ ├── cfn-template-param.yml │ │ │ ├── cfn-template.yml │ │ │ └── org-template.yml │ ├── valid-basic.yml │ ├── valid-include.yml │ └── valid-regular-cloudformation.yml ├── tsconfig.json ├── unit-tests │ ├── aws-provider │ │ ├── aws-events.test-off │ │ ├── aws-organization-reader.organizational-units.test-off │ │ ├── aws-organization-writer.accounts.test-off │ │ └── aws-organization-writer.organizational-units.test-off │ ├── build-tasks │ │ ├── build-configuration.test.ts │ │ └── build-task-provider.test.ts │ ├── cfn-binder │ │ ├── actions.test.ts │ │ ├── cfn-binder.test.ts │ │ ├── cfn-parameters.test.ts │ │ ├── cfn-template.test.ts │ │ ├── cloudtrail.test.ts │ │ ├── defaults.test.ts │ │ ├── foreach.test.ts │ │ └── references.test.ts │ ├── cfn-runner │ │ └── cfn-task-runner.test.ts │ ├── cfn-types.ts │ ├── cli-program.test.ts │ ├── commands │ │ ├── cleanup.test.ts │ │ ├── create-organization-changeset.test.ts │ │ ├── describe-stacks.test.ts │ │ ├── execute-organization-changeset.test.ts │ │ ├── init-organization-pipeline.test.ts │ │ ├── init-organization.test.ts │ │ ├── perform-tasks.test.ts │ │ ├── print-change-set.ts │ │ ├── print-org.test.ts │ │ ├── print-stacks.test.ts │ │ ├── print-tasks.test.ts │ │ ├── update-stacks.test.ts │ │ ├── update.test.ts │ │ └── validate-stacks.test.ts │ ├── core │ │ ├── cfn-expression-resolver-find-in-map.test.ts │ │ ├── cfn-expression-resolver.test.ts │ │ ├── cfn-functions │ │ │ └── cfn-json-string.test.ts │ │ ├── cfn-parameters.test.ts │ │ └── default-cfn-expression-resolver.test.ts │ ├── org-binder │ │ ├── org-binder.test.ts │ │ └── org-task-provider.test.ts │ ├── parser │ │ ├── model │ │ │ ├── account-resource.test.ts │ │ │ ├── cloudformation-resource.test.ts │ │ │ ├── master-account-resource.test.ts │ │ │ ├── organization-root.test.ts │ │ │ ├── organizational-unit-resource.test.ts │ │ │ ├── password-policy-resource.test.ts │ │ │ └── service-control-policy-resource.test.ts │ │ ├── parser.bindings.test.ts │ │ ├── parser.files.test.ts │ │ ├── parser.references.test.ts │ │ ├── parser.validation.test.ts │ │ └── validator.test.ts │ ├── plugin │ │ ├── impl │ │ │ ├── cdk-build-task-plugin.test.ts │ │ │ ├── rp-build-task-plugin.test.ts │ │ │ ├── s3-copy-build-task-plugin.test-off │ │ │ └── sls-build-task-plugin.test.ts │ │ ├── plugin-command.test.ts │ │ └── plugin.test.ts │ ├── state │ │ ├── persisted-state-migration.test.ts │ │ └── persisted-state.test.ts │ ├── templates │ │ ├── budget-alarms.test.ts │ │ ├── cfn-template.org-functions.test.ts │ │ ├── conditionals.test.ts │ │ ├── custom-parameter-binding.ts │ │ ├── default-organization-bindings.test.ts │ │ ├── depends-on.test.ts │ │ ├── dependson-account.test.ts │ │ ├── enum-expressions.test.ts │ │ ├── hostedzone-per-account.test.ts │ │ ├── organization-binding.test.ts │ │ ├── organization-bindings-section.test.ts │ │ └── tasks.test.ts │ ├── test-organizations.ts │ ├── test-templates.ts │ ├── util │ │ ├── aws-config-file │ │ ├── aws-shared-credentials-file │ │ ├── console-util.test.ts │ │ ├── global-state.test.ts │ │ └── resource-util.test.ts │ └── writer │ │ └── default-template-writer.test.ts └── validation │ └── validate-examples.test.ts └── tsconfig.json /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Subject of the issue 2 | Describe your issue here. 3 | 4 | ### Your environment 5 | * version of org-foramtion (ofn --version) 6 | * version of node (node --version) 7 | * which OS/distro 8 | 9 | ### Steps to reproduce 10 | Tell us how to reproduce this issue. Please provide ofn projct files if possible, 11 | you can use [this template](https://plnkr.co/edit/m568SDw2KPufQsUl?p=preview) as a base. 12 | https://plnkr.co/edit/m568SDw2KPufQsUl 13 | 14 | ### Expected behaviour 15 | Tell us what should happen 16 | 17 | ### Actual behaviour 18 | Tell us what happens instead 19 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | 4 | # Maintain dependencies for GitHub Actions 5 | - package-ecosystem: "github-actions" 6 | directory: "/" 7 | schedule: 8 | interval: "weekly" 9 | open-pull-requests-limit: 3 10 | 11 | # Maintain dependencies for npm 12 | - package-ecosystem: "npm" 13 | directory: "/" 14 | schedule: 15 | interval: "weekly" 16 | open-pull-requests-limit: 3 17 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Linting / Unit Tests 3 | 4 | on: 5 | pull_request: 6 | branches: 7 | - master 8 | push: 9 | branches: 10 | - master 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: actions/setup-node@v4 18 | with: 19 | node-version: 18 20 | - name: Install Dependencies with NPM 21 | id: installation 22 | run: | 23 | npm ci --no-optional 24 | - name: Run Tests 25 | id: testing 26 | run: | 27 | npm run lint 28 | npm run test:ci 29 | - name: Add Coverage Report 30 | if: github.event_name == 'pull_request' 31 | id: coverage-report 32 | uses: 5monkeys/cobertura-action@v14 33 | continue-on-error: true 34 | with: 35 | path: coverage/cobertura-coverage.xml 36 | repo_token: ${{ secrets.GITHUB_TOKEN }} 37 | minimum_coverage: 40 38 | - name: Upload Artifacts 39 | id: upload-artifacts 40 | uses: actions/upload-artifact@v4 41 | with: 42 | name: artifacts 43 | path: coverage -------------------------------------------------------------------------------- /.github/workflows/container.yaml: -------------------------------------------------------------------------------- 1 | name: container 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Create additional environment variables 14 | run: | 15 | # get the tag and remove 'v' prefix 16 | TAG=${GITHUB_REF//refs\/tags\//} 17 | echo "RELEASE_VERSION=${TAG//v/}" >> $GITHUB_ENV 18 | - name: Set up QEMU 19 | uses: docker/setup-qemu-action@v3 20 | - name: Set up Docker Buildx 21 | uses: docker/setup-buildx-action@v3 22 | - name: Login to DockerHub 23 | uses: docker/login-action@v3 24 | with: 25 | username: ${{ secrets.DOCKER_USERNAME }} 26 | password: ${{ secrets.DOCKER_TOKEN }} 27 | - name: Build and publish container 28 | uses: docker/build-push-action@v6 29 | with: 30 | build-args: RELEASE_VERSION=${{ env.RELEASE_VERSION }} 31 | platforms: linux/amd64,linux/arm64 32 | push: true 33 | tags: | 34 | ${{ secrets.DOCKER_REPOSITORY }}:latest 35 | ${{ secrets.DOCKER_REPOSITORY }}:${{ env.RELEASE_VERSION }} 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | output 3 | test/integration-tests/temp 4 | dist 5 | .vscode 6 | temp 7 | chainslayer 8 | .nyc_output 9 | work 10 | .DS_Store 11 | coverage/ 12 | examples/automation/create-account/variables.yml 13 | oc 14 | test/.ts 15 | tmp/ 16 | .nunjucks-debug 17 | .terraform 18 | .terraform.lock.hcl 19 | terraform.tfstate 20 | terraform.tfstate.backup -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine 2 | # release version passed in on build, just default it temporarily 3 | ARG RELEASE_VERSION=0.0.1 4 | RUN npm install -g --production aws-organization-formation@${RELEASE_VERSION} 5 | WORKDIR /workdir 6 | ENV AWS_PROFILE=default 7 | ENTRYPOINT [ "org-formation" ] 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 OlafConijn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect -------------------------------------------------------------------------------- /docs/articles/aws-organizations/cross-account-resource.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/articles/aws-organizations/cross-account-resource.png -------------------------------------------------------------------------------- /docs/articles/aws-organizations/cross-account-service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/articles/aws-organizations/cross-account-service.png -------------------------------------------------------------------------------- /docs/articles/aws-organizations/dev-prod-accounts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/articles/aws-organizations/dev-prod-accounts.png -------------------------------------------------------------------------------- /docs/articles/aws-organizations/organization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/articles/aws-organizations/organization.png -------------------------------------------------------------------------------- /docs/diagrams/CIS benchmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/diagrams/CIS benchmark.png -------------------------------------------------------------------------------- /docs/diagrams/breakglass role.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/diagrams/breakglass role.png -------------------------------------------------------------------------------- /docs/diagrams/budgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/diagrams/budgets.png -------------------------------------------------------------------------------- /docs/diagrams/guardduty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/diagrams/guardduty.png -------------------------------------------------------------------------------- /docs/features.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/features.pdf -------------------------------------------------------------------------------- /docs/img/chainslayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/img/chainslayer.png -------------------------------------------------------------------------------- /docs/img/feature-1-update-org.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/img/feature-1-update-org.png -------------------------------------------------------------------------------- /docs/img/feature-2-update-stacks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/img/feature-2-update-stacks.png -------------------------------------------------------------------------------- /docs/img/feature-3-perform-tasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/img/feature-3-perform-tasks.png -------------------------------------------------------------------------------- /docs/img/govcloud-org-formation-init.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/img/govcloud-org-formation-init.png -------------------------------------------------------------------------------- /docs/img/govcloud-org-formation-perform-tasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/img/govcloud-org-formation-perform-tasks.png -------------------------------------------------------------------------------- /docs/img/govcloud-org-formation-update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/img/govcloud-org-formation-update.png -------------------------------------------------------------------------------- /docs/img/org-formation-init.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/img/org-formation-init.png -------------------------------------------------------------------------------- /docs/img/stedi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/docs/img/stedi.png -------------------------------------------------------------------------------- /docs/least-priviledge.md: -------------------------------------------------------------------------------- 1 | this is a placeholder for now. best place to read about least privilege is here: https://github.com/org-formation/org-formation-cli/issues/120 2 | -------------------------------------------------------------------------------- /docs/organizationAccountAccessRole.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: 'Creates the OrganizationAccountAccessRole for cross account access' 3 | 4 | Parameters: 5 | 6 | masterAccountId: 7 | Type: String 8 | 9 | Resources: 10 | Role: 11 | Type: AWS::IAM::Role 12 | Properties: 13 | ManagedPolicyArns: 14 | - arn:aws:iam::aws:policy/AdministratorAccess 15 | RoleName: OrganizationAccountAccessRole 16 | AssumeRolePolicyDocument: 17 | Version: 2012-10-17 18 | Statement: 19 | - Effect: Allow 20 | Action: sts:AssumeRole 21 | Principal: 22 | AWS: !Ref masterAccountId -------------------------------------------------------------------------------- /examples/automation/create-account/.gitignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless -------------------------------------------------------------------------------- /examples/automation/create-account/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-account", 3 | "version": "1.0.0", 4 | "description": "this project will automate the process that needs to follow account creation", 5 | "main": "handler.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Olaf Conijn", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "aws-sdk": "^2.1354.0", 13 | "serverless-step-functions": "^2.29.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/automation/create-account/readme.md: -------------------------------------------------------------------------------- 1 | # Custom Account Creation Workflow 2 | 3 | Example [serverless.com](http://www.serverless.com) project that will use StepFunctions send an email after account is created. This is intended as an example do demonstrate how to automate and extend the account creation process. 4 | 5 | Custom account creation workflows are implemented using a CloudWatch/EventBridge rule. Use the following event pattern to subscribe to `AccountCreated` events (must be `us-east-1`) 6 | 7 | ``` yaml 8 | EventPattern: 9 | source: 10 | - oc.org-formation 11 | detail: 12 | eventName: 13 | - AccountCreated 14 | ``` 15 | 16 | **Note** that currently events are published in the `us-east-1` region. If you would like events to be raised in a different region, please raise a ticket: https://github.com/OlafConijn/AwsOrganizationFormation/issues 17 | 18 | In your organization you might want to do something a lot less manual: automatically create a ticket, update a wiki or perform tasks in the created account. Maybe integrate a library like [https://github.com/sentialabs/coto](https://github.com/sentialabs/coto)? 19 | 20 | Overview 21 | 22 | ![account-creation](../../img/account-creation.png) 23 | -------------------------------------------------------------------------------- /examples/eventbus/organization-tasks.yml: -------------------------------------------------------------------------------- 1 | CentralBusExample: 2 | Type: update-stacks 3 | Template: ./central-bus.yml 4 | StackName: central-bus 5 | Parameters: 6 | principalOrgId: !Ref ORG::PrincipalOrgID 7 | DefaultOrganizationBindingRegion: us-east-1 8 | OrganizationBindings: 9 | CentralAccountBinding: 10 | Account: !Ref CentralAccount 11 | SourceAccountsBinding: 12 | Account: "*" 13 | ExcludeAccount: !Ref CentralAccount -------------------------------------------------------------------------------- /examples/img/account-creation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/img/account-creation.png -------------------------------------------------------------------------------- /examples/img/budget-alarms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/img/budget-alarms.png -------------------------------------------------------------------------------- /examples/img/cloudtrail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/img/cloudtrail.png -------------------------------------------------------------------------------- /examples/img/cross-account-bucket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/img/cross-account-bucket.png -------------------------------------------------------------------------------- /examples/img/cross-account-lambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/img/cross-account-lambda.png -------------------------------------------------------------------------------- /examples/img/cross-account-role-with-alarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/img/cross-account-role-with-alarm.png -------------------------------------------------------------------------------- /examples/img/cross-account-role.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/img/cross-account-role.png -------------------------------------------------------------------------------- /examples/img/cross-account-secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/img/cross-account-secret.png -------------------------------------------------------------------------------- /examples/img/guardduty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/img/guardduty.png -------------------------------------------------------------------------------- /examples/img/organization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/img/organization.png -------------------------------------------------------------------------------- /examples/img/subdomains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/img/subdomains.png -------------------------------------------------------------------------------- /examples/img/terraform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/img/terraform.png -------------------------------------------------------------------------------- /examples/img/wildcard-certs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/img/wildcard-certs.png -------------------------------------------------------------------------------- /examples/lambda-using-read-file/lambda-using-read-file.yml: -------------------------------------------------------------------------------- 1 | 2 | AWSTemplateFormatVersion: 2010-09-09-OC 3 | Description: Org formation example 4 | 5 | Resources: 6 | MyRole: 7 | Type: AWS::IAM::Role 8 | Properties: 9 | ManagedPolicyArns: 10 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 11 | AssumeRolePolicyDocument: 12 | Version: '2012-10-17' 13 | Statement: 14 | - Effect: Allow 15 | Principal: 16 | Service: 17 | - lambda.amazonaws.com 18 | Action: 19 | - 'sts:AssumeRole' 20 | 21 | MyLambda: 22 | Type: AWS::Lambda::Function 23 | Properties: 24 | FunctionName: 'org-formation-example-lambda-using-read-file' 25 | Code: 26 | ZipFile: !ReadFile './src/index.js' 27 | Handler: index.handler 28 | Role: !GetAtt MyRole.Arn 29 | Runtime: nodejs12.x 30 | -------------------------------------------------------------------------------- /examples/lambda-using-read-file/organization-tasks.yml: -------------------------------------------------------------------------------- 1 | # this example uses features that are part of the 0.9.13 release 2 | 3 | OrganizationUpdate: 4 | Type: update-organization 5 | Skip: true 6 | Template: ./organization.yml 7 | 8 | DeployCodeAndLambda: 9 | Type: update-stacks 10 | Template: ./lambda-using-read-file.yml 11 | StackName: org-formation-example-lambda-using-read-file 12 | DefaultOrganizationBinding: 13 | Account: !Ref AccountA 14 | Region: eu-central-1 15 | 16 | -------------------------------------------------------------------------------- /examples/lambda-using-read-file/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Organization: 4 | MasterAccount: 5 | Type: OC::ORG::MasterAccount 6 | Properties: 7 | AccountId: '102625093955' 8 | RootEmail: org-master@olafconijn.awsapps.com 9 | AccountName: Organization Master Account 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /examples/lambda-using-read-file/src/index.js: -------------------------------------------------------------------------------- 1 | 2 | exports.handler = function (event, context) { 3 | console.log(event); 4 | context.succeed('hello ' + event.name); 5 | }; 6 | -------------------------------------------------------------------------------- /examples/lambda-using-uploaded-zip/lambda-template-using-zip.yml: -------------------------------------------------------------------------------- 1 | 2 | AWSTemplateFormatVersion: 2010-09-09-OC 3 | Description: Org formation example 4 | 5 | Parameters: 6 | 7 | deploymentBucketName: 8 | Type: String 9 | Description: Name of the bucket that contains the lambda source code 10 | 11 | lambdaS3Key: 12 | Type: String 13 | Description: S3 Key that contains the location of lambda source code 14 | 15 | Resources: 16 | MyRole: 17 | Type: AWS::IAM::Role 18 | Properties: 19 | ManagedPolicyArns: 20 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 21 | AssumeRolePolicyDocument: 22 | Version: '2012-10-17' 23 | Statement: 24 | - Effect: Allow 25 | Principal: 26 | Service: 27 | - lambda.amazonaws.com 28 | Action: 29 | - 'sts:AssumeRole' 30 | 31 | MyLambda: 32 | Type: AWS::Lambda::Function 33 | Properties: 34 | FunctionName: 'org-formation-example-lambda-using-uploaded-zip' 35 | Code: 36 | S3Bucket: !Ref deploymentBucketName 37 | S3Key: !Ref lambdaS3Key 38 | Handler: index.handler 39 | Role: !GetAtt MyRole.Arn 40 | Runtime: nodejs12.x 41 | -------------------------------------------------------------------------------- /examples/lambda-using-uploaded-zip/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Organization: 4 | MasterAccount: 5 | Type: OC::ORG::MasterAccount 6 | Properties: 7 | AccountId: '102625093955' 8 | RootEmail: org-master@olafconijn.awsapps.com 9 | AccountName: Organization Master Account 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /examples/lambda-using-uploaded-zip/src/index.js: -------------------------------------------------------------------------------- 1 | const logger = require('./logger') 2 | 3 | exports.handler = function (event, context) { 4 | logger.log(event); 5 | context.succeed('hello ' + event.name); 6 | }; 7 | -------------------------------------------------------------------------------- /examples/lambda-using-uploaded-zip/src/logger.js: -------------------------------------------------------------------------------- 1 | 2 | exports.log = function (x) { 3 | console.log(x); 4 | }; 5 | -------------------------------------------------------------------------------- /examples/lambda-using-uploaded-zip/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "org-formation-example-lambda", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "run-local.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC" 11 | } 12 | -------------------------------------------------------------------------------- /examples/lambda-using-uploaded-zip/src/run-local.js: -------------------------------------------------------------------------------- 1 | const lambda = require('./index'); 2 | 3 | const event = {name: 'me'}; 4 | const context = { 5 | succeed: (x) => console.log(`succeeded: ${x}`) 6 | } 7 | lambda.handler(event, context) -------------------------------------------------------------------------------- /examples/secure-defaults/secure-defaults-template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | 3 | # Section that contains a named list of Bindings. 4 | # Bindings determine what resources are deployed where 5 | # These bindings can be !Ref'd from the Resources in the resource section 6 | OrganizationBindings: 7 | 8 | # Binding for: S3AccountPublicAccessBlock 9 | PrimaryRegionsBinding: 10 | 11 | # Binding for: EbsEncryptionDefaults 12 | AllRegionsBinding: 13 | 14 | Resources: 15 | 16 | S3AccountPublicAccessBlock: 17 | Type: 'Community::S3::PublicAccessBlock' 18 | OrganizationBinding: !Ref PrimaryRegionsBinding 19 | Properties: 20 | BlockPublicAcls: true 21 | BlockPublicPolicy: true 22 | IgnorePublicAcls: true 23 | RestrictPublicBuckets: true 24 | 25 | EbsEncryptionDefaults: 26 | Type: 'Community::Organizations::EbsEncryptionDefaults' 27 | OrganizationBinding: !Ref AllRegionsBinding 28 | Properties: 29 | EnableEbsEncryptionByDefault: true -------------------------------------------------------------------------------- /examples/security-hub/security-hub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/security-hub/security-hub.png -------------------------------------------------------------------------------- /examples/security-hub/templates/secure-defaults.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | 3 | # Section that contains a named list of Bindings. 4 | # Bindings determine what resources are deployed where 5 | # These bindings can be !Ref'd from the Resources in the resource section 6 | OrganizationBindings: 7 | # Binding for: S3AccountPublicAccessBlock 8 | PrimaryRegionBinding: 9 | 10 | # Binding for: EbsEncryptionDefaults 11 | AllRegionsBinding: 12 | 13 | Resources: 14 | S3AccountPublicAccessBlock: 15 | Type: "Community::S3::PublicAccessBlock" 16 | OrganizationBinding: !Ref PrimaryRegionBinding 17 | Properties: 18 | BlockPublicAcls: true 19 | BlockPublicPolicy: true 20 | IgnorePublicAcls: true 21 | RestrictPublicBuckets: true 22 | 23 | EbsEncryptionDefaults: 24 | Type: "Community::Organizations::EbsEncryptionDefaults" 25 | OrganizationBinding: !Ref AllRegionsBinding 26 | Properties: 27 | EnableEbsEncryptionByDefault: true 28 | 29 | NoDefaultVPC: 30 | OrganizationBinding: !Ref AllRegionsBinding 31 | Type: Community::Organizations::NoDefaultVPC 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /examples/security-hub/templates/security-hub-insights.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09-OC 2 | 3 | Resources: 4 | 5 | FindingsByResourceType: 6 | Type: 'Community::SecurityHub::Insight' 7 | Properties: 8 | InsightName: "0a. Findings by Resource Type" # use 0x. to ensure the insight ends up on the first page 9 | GroupByAttribute: ResourceType 10 | FiltersJSON: !Sub '{ 11 | "ComplianceStatus": [ 12 | { "Value": "FAILED", "Comparison": "EQUALS" } 13 | ], 14 | "WorkflowStatus": [ 15 | { "Value": "NEW", "Comparison": "EQUALS" }, 16 | { "Value": "NOTIFIED", "Comparison": "EQUALS" } 17 | ], 18 | "RecordState": [ 19 | { "Value": "ACTIVE", "Comparison": "EQUALS" } 20 | ] 21 | }' 22 | -------------------------------------------------------------------------------- /examples/service-quotas/organization-tasks.yml: -------------------------------------------------------------------------------- 1 | # note: register-type task is only supported in AWS Organization Formation v. 0.9.10 (or higher) 2 | 3 | Parameters: 4 | 5 | # template uses region in various tasks. 6 | # declaring region here so there is a single point of definition 7 | region: 8 | Type: String 9 | Default: us-east-1 10 | 11 | 12 | OrganizationUpdate: 13 | Type: update-organization 14 | Skip: true 15 | Template: ../organization.yml 16 | 17 | # include that contains the tasks for registering cloudformation types. 18 | # registering a type takes long, hence the 'MaxConcurrentTasks: 10' 19 | RegisterTypes: 20 | Type: include 21 | Path: register-type-tasks.yml 22 | MaxConcurrentTasks: 10 23 | Parameters: 24 | region: !Ref region 25 | 26 | # task that deploys a stack that contains service quota values. 27 | # the values in this sample equal the default values. therefore no service quota changes are requested 28 | Quotas: 29 | Type: update-stacks 30 | DependsOn: 31 | - RegisterTypes 32 | Template: ./service-quotas-template.yml 33 | StackName: service-quotas 34 | MaxConcurrentStacks: 10 35 | DefaultOrganizationBinding: 36 | IncludeMasterAccount: true 37 | Account: '*' 38 | Region: !Ref region 39 | -------------------------------------------------------------------------------- /examples/service-quotas/register-type-tasks.yml: -------------------------------------------------------------------------------- 1 | # note: register-type task is only supported in AWS Organization Formation v. 0.9.10 (or higher) 2 | 3 | Parameters: 4 | # template uses region in various tasks. 5 | # declaring region here so there is a single point of definition 6 | region: 7 | Type: String 8 | Default: us-east-1 9 | 10 | 11 | # registration of Community::ServiceQuotas::CloudFormation 12 | ServiceQuotasCloudFormationRP: 13 | Type: register-type 14 | SchemaHandlerPackage: s3://community-resource-provider-catalog/community-servicequotas-cloudformation-0.1.0.zip 15 | ResourceType: 'Community::ServiceQuotas::CloudFormation' 16 | MaxConcurrentTasks: 10 17 | OrganizationBinding: 18 | IncludeMasterAccount: true 19 | Account: '*' 20 | Region: !Ref region 21 | 22 | # registration of Community::ServiceQuotas::S3 23 | ServiceQuotasS3RP: 24 | Type: register-type 25 | SchemaHandlerPackage: s3://community-resource-provider-catalog/community-servicequotas-s3-0.1.0.zip 26 | ResourceType: 'Community::ServiceQuotas::S3' 27 | MaxConcurrentTasks: 10 28 | OrganizationBinding: 29 | IncludeMasterAccount: true 30 | Account: '*' 31 | Region: !Ref region -------------------------------------------------------------------------------- /examples/service-quotas/service-quotas-template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Resources: 3 | CloudFormationQuotas: 4 | Type: 'Community::ServiceQuotas::CloudFormation' 5 | Properties: 6 | Stacks: 200 7 | 8 | S3Quotas: 9 | Type: 'Community::ServiceQuotas::S3' 10 | Properties: 11 | Buckets: 100 12 | -------------------------------------------------------------------------------- /examples/sso/img/sso.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/examples/sso/img/sso.png -------------------------------------------------------------------------------- /examples/sso/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 507468909204 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organization Master Account 9 | RootEmail: olaf@email.com 10 | AccountId: '507468909204' 11 | 12 | SharedUsersAccount: 13 | Type: OC::ORG::Account 14 | Properties: 15 | RootEmail: users-2@olafconijn.awsapps.com 16 | AccountName: Shared Users Account 17 | 18 | DevelopmentAccount: 19 | Type: OC::ORG::Account 20 | Properties: 21 | AccountName: Development Account 22 | RootEmail: dev-account-1@olafconijn.awsapps.com 23 | 24 | Production1Account: 25 | Type: OC::ORG::Account 26 | Properties: 27 | AccountName: Production Account 28 | RootEmail: production1@olafconijn.awsapps.com -------------------------------------------------------------------------------- /examples/sso/readme.md: -------------------------------------------------------------------------------- 1 | 2 | ## SSO Implementation 3 | 4 | This folder contains a task file and templates that make a good starting point for implementing SSO. 5 | 6 | ![SSO](img/sso.png) 7 | -------------------------------------------------------------------------------- /examples/sso/templates/generic-sns.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Parameters: 4 | 5 | resourcePrefix: 6 | Type: String 7 | 8 | topicName: 9 | Type: String 10 | 11 | topicDisplayName: 12 | Type: String 13 | 14 | subscriptionProtocol: 15 | Type: String 16 | 17 | subscriptionEndpoint: 18 | Type: String 19 | 20 | Resources: 21 | 22 | Topic: 23 | Type: AWS::SNS::Topic 24 | Properties: 25 | DisplayName: !Ref topicDisplayName 26 | TopicName: !Sub '${resourcePrefix}-${topicName}' 27 | Subscription: 28 | - Endpoint: !Ref subscriptionEndpoint 29 | Protocol: !Ref subscriptionProtocol 30 | 31 | Outputs: 32 | 33 | TopicArn: 34 | Description: The ARN of the Topic 35 | Value: !Ref Topic 36 | Export: 37 | Name: !Sub '${AWS::StackName}-arn' 38 | -------------------------------------------------------------------------------- /examples/sso/templates/sso-custom-policies.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | 3 | Parameters: 4 | 5 | resourcePrefix: 6 | Type: String 7 | 8 | Resources: 9 | 10 | ExamplePolicy: 11 | Type: AWS::IAM::ManagedPolicy 12 | Properties: 13 | ManagedPolicyName: !Sub '${resourcePrefix}-example-policy' 14 | Path: / 15 | PolicyDocument: 16 | Version: 2012-10-17 17 | Statement: 18 | - Sid: DenyExample 19 | Effect: Deny 20 | Action: s3:put* 21 | Resource: 'arn:aws:s3:::just-an-example/*' 22 | 23 | Outputs: 24 | 25 | ExamplePolicyArn: 26 | Description: The ARN of the example policy 27 | Value: !Ref ExamplePolicy 28 | Export: 29 | Name: !Sub '${AWS::StackName}-example-arn' 30 | -------------------------------------------------------------------------------- /examples/templating/organization-tasks.yaml: -------------------------------------------------------------------------------- 1 | 2 | SecurityGroupExample: 3 | Type: update-stacks 4 | Template: ./security-group.njk 5 | StackName: SecurityGroupExample 6 | TemplatingContext: 7 | ports: 8 | - 22 9 | - 80 10 | DefaultOrganizationBinding: 11 | Account: "*" 12 | Region: us-east-1 -------------------------------------------------------------------------------- /examples/templating/security-group.njk: -------------------------------------------------------------------------------- 1 | Description: Nunjucks Security group template 2 | AWSTemplateFormatVersion: 2010-09-09 3 | Resources: 4 | SecurityGroup: 5 | Type: 'AWS::EC2::SecurityGroup' 6 | Properties: 7 | GroupDescription: "Open ports for incoming traffic" 8 | VpcId: "vpc-1234ABC" 9 | SecurityGroupIngress: 10 | {% for port in ports %} 11 | - CidrIp: "0.0.0.0/0" 12 | FromPort: {{ port }} 13 | ToPort: {{ port }} 14 | IpProtocol: tcp 15 | {% endfor %} -------------------------------------------------------------------------------- /examples/terraform/bucket/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | backend "s3" { 3 | } 4 | } 5 | 6 | provider "aws" {} 7 | 8 | variable "tfvarforbucketname" {} 9 | 10 | resource "aws_s3_bucket" "b" { 11 | bucket = var.tfvarforbucketname 12 | 13 | tags = { 14 | ManagedBy = "Terraform" 15 | DeployedWith = "org-formation" 16 | } 17 | } -------------------------------------------------------------------------------- /examples/terraform/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Organization: 4 | MasterAccount: 5 | Type: OC::ORG::MasterAccount 6 | Properties: 7 | AccountId: '102625093955' 8 | RootEmail: org-master@olafconijn.awsapps.com 9 | AccountName: Organization Master Account 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /not-supported.md: -------------------------------------------------------------------------------- 1 | 2 | **Constrains or things that are otherwise not supported (yet)** 3 | 4 | If you feel it is important to support these scenarios, please post an enhancement or make a pull request! 5 | 6 | **in general** 7 | - it is not possible to run org-formation on windows 8 | 9 | **within the organization section**: 10 | - it is not possible to create multiple organization roots 11 | - it is not possible to have tag names with spaces 12 | - it is not possible to more than 1 account alias per account 13 | 14 | -------------------------------------------------------------------------------- /resources/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | phases: 3 | install: 4 | commands: 5 | - npm install aws-organization-formation@"<1.1.0" -g 6 | - echo installed aws-organization-formation 7 | - org-formation -v 8 | build: 9 | commands: 10 | - org-formation perform-tasks ./organization-tasks.yml --no-color XXX-ARGS 11 | post_build: 12 | commands: 13 | - echo Build completed 14 | -------------------------------------------------------------------------------- /resources/initial-commit/.org-formationrc: -------------------------------------------------------------------------------- 1 | organizationFile = ./organization.yml -------------------------------------------------------------------------------- /resources/local-build-orgformation-tasks.yml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | <<: !Include "../organization-parameters.yml" 3 | 4 | resourcePrefix: # overwrite the resource prefix specified in ../organization-parameters 5 | Type: String 6 | Default: XXX-resourcePrefix 7 | 8 | OrganizationUpdate: 9 | Type: update-organization 10 | Template: ../organization.yml 11 | 12 | OrganizationBuildPipeline: 13 | Type: update-stacks 14 | Template: ./org-formation-build.yml 15 | StackName: XXX-stackName 16 | StackDescription: Organization Formation Build Infrastructure (CodeCommit, CodeBuild and CodePipeline) 17 | Parameters: 18 | stateBucketName: !Ref stateBucketName 19 | resourcePrefix: !Ref resourcePrefix 20 | repositoryName: XXX-repositoryName 21 | DefaultOrganizationBindingRegion: !Ref primaryRegion 22 | DefaultOrganizationBinding: 23 | IncludeMasterAccount: true -------------------------------------------------------------------------------- /resources/organization-parameters.yml: -------------------------------------------------------------------------------- 1 | resourcePrefix: 2 | Type: String 3 | Default: my # if you use this resource prefix in all stacks deployed by this project they are easily identifiable 4 | 5 | primaryRegion: 6 | Type: String 7 | Default: XXX-region 8 | 9 | allRegions: 10 | Type: List 11 | Default: # sometimes you will need to deploy a task to all regions you allow. you can use this parameter to keep that list in 1 place 12 | - XXX-region 13 | # - us-east-1 14 | 15 | stateBucketName: 16 | Type: String 17 | Default: XXX-stateBucketName 18 | -------------------------------------------------------------------------------- /resources/orgformation-build-access-role.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | 3 | Parameters: 4 | 5 | assumeRolePrincipal: 6 | Type: String 7 | 8 | Resources: 9 | OrganizationFormationBuildAccessRole: 10 | Type: AWS::IAM::Role 11 | Properties: 12 | ManagedPolicyArns: 13 | - arn:aws:iam::aws:policy/AdministratorAccess # see: https://github.com/org-formation/org-formation-cli/blob/master/docs/least-priviledge.md 14 | RoleName: XXX-OrganizationFormationBuildAccessRole 15 | AssumeRolePolicyDocument: 16 | Version: 2012-10-17 17 | Statement: 18 | - Effect: Allow 19 | Action: sts:AssumeRole 20 | Principal: 21 | AWS: !Ref assumeRolePrincipal -------------------------------------------------------------------------------- /src/aws-provider/aws-account-access.ts: -------------------------------------------------------------------------------- 1 | import { AwsUtil } from '~util/aws-util'; 2 | import { GlobalState } from '~util/global-state'; 3 | 4 | export interface ICrossAccountAccess { 5 | role?: string; 6 | viaRole?: string; 7 | } 8 | 9 | export interface ICrossAccountConfig { 10 | masterAccountId: string; 11 | masterAccountRoleName: string; 12 | } 13 | 14 | 15 | export const GetOrganizationAccessRoleInTargetAccount = async (config: ICrossAccountConfig, targetAccountId: string): Promise => { 16 | if (config && config.masterAccountId === targetAccountId) { 17 | if (config.masterAccountRoleName !== undefined) { 18 | return { 19 | role: config.masterAccountRoleName, 20 | }; 21 | } 22 | else { 23 | return {}; 24 | } 25 | } else { 26 | const result: ICrossAccountAccess = { 27 | role: GlobalState.GetOrganizationAccessRoleName(targetAccountId), 28 | }; 29 | if (config && config.masterAccountRoleName !== undefined && ! (await AwsUtil.GetBuildRunningOnMasterAccount())) { 30 | result.viaRole = AwsUtil.GetRoleArn(config.masterAccountId, config.masterAccountRoleName); 31 | } 32 | return result; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /src/aws-provider/util.ts: -------------------------------------------------------------------------------- 1 | import { ConsoleUtil } from '~util/console-util'; 2 | 3 | export const performAndRetryIfNeeded = async (fn: () => Promise): Promise => { 4 | let shouldRetry = false; 5 | let retryCount = 0; 6 | do { 7 | shouldRetry = false; 8 | try { 9 | return await fn(); 10 | } catch (err) { 11 | if (err && (err.name === 'ConcurrentModificationException' || err.name === 'TooManyRequestsException') && retryCount < 30) { 12 | retryCount = retryCount + 1; 13 | shouldRetry = true; 14 | const wait = retryCount + (0.5 * Math.random()); 15 | ConsoleUtil.LogDebug(`received retryable error ${err.name}. wait ${wait} and retry-count ${retryCount}`); 16 | await sleep(wait * 1000); 17 | continue; 18 | } 19 | throw err; 20 | } 21 | } 22 | while (shouldRetry); 23 | }; 24 | 25 | export const sleep = (time: number): Promise => { 26 | return new Promise(resolve => setTimeout(resolve, time)); 27 | }; 28 | -------------------------------------------------------------------------------- /src/cfn-binder/cfn-parameters.ts: -------------------------------------------------------------------------------- 1 | import { ICfnExpression } from '~core/cfn-expression'; 2 | import { CfnExpressionResolver } from '~core/cfn-expression-resolver'; 3 | 4 | export class CfnParameters { 5 | 6 | static async resolveParameters(parameters: Record, resolver: CfnExpressionResolver): Promise> { 7 | const result: Record = {}; 8 | for(const [name, expression] of Object.entries(parameters)) { 9 | if (Array.isArray(expression)) { 10 | const resolved = await Promise.all(expression.map(x=>resolver.resolveSingleExpression(x, 'parameter ' + name))); 11 | result[name] = resolved.join(','); 12 | } else { 13 | const value = await resolver.resolveSingleExpression(expression, 'parameter ' + name); 14 | result[name] = '' + value; 15 | } 16 | } 17 | return result; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/commands/index.ts: -------------------------------------------------------------------------------- 1 | export * from './base-command'; 2 | export * from './create-organization-changeset'; 3 | export * from './delete-stacks'; 4 | export * from './describe-stacks'; 5 | export * from './execute-organization-changeset'; 6 | export * from './init-organization-pipeline'; 7 | export * from './init-organization'; 8 | export * from './perform-tasks'; 9 | export * from './print-changeset'; 10 | export * from './print-org'; 11 | export * from './print-stacks'; 12 | export * from './update-organization'; 13 | export * from './update-stacks'; 14 | export * from './validate-stacks'; 15 | export * from './validate-tasks'; 16 | export * from './remove'; 17 | -------------------------------------------------------------------------------- /src/core/cfn-expression.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface ICfnCopyValue { 'Fn::CopyValue': string[] } 3 | export interface ICfnRefExpression { Ref: string } 4 | export interface ICfnGetAttExpression { 'Fn::GetAtt': string[] } 5 | export interface ICfnJoinExpression { 'Fn::Join': ICfnExpression[] } 6 | export interface ICfnFindInMapExpression { 'Fn::FindInMap': ICfnExpression[] } 7 | export interface ICfnSubExpression { 'Fn::Sub': any } 8 | export interface ICfnMD5Expression { 'Fn::MD5': string } 9 | export interface ICfnReadFileExpression { 'Fn::ReadFile': string } 10 | export interface ICfnCmdExpression { 'Fn::Cmd': string } 11 | export type ICfnExpression = string | ICfnRefExpression | ICfnFindInMapExpression | ICfnGetAttExpression | ICfnJoinExpression | ICfnSubExpression | ICfnCopyValue; 12 | -------------------------------------------------------------------------------- /src/core/cfn-functions/cfn-cmd.ts: -------------------------------------------------------------------------------- 1 | import { execSync } from 'child_process'; 2 | import { ICfnFunctionContext } from './cfn-functions'; 3 | import { OrgFormationError } from '~org-formation-error'; 4 | 5 | export class CfnCmd { 6 | 7 | static resolve(context: ICfnFunctionContext, resource: any, resourceParent: any, resourceKey: string, key: string, val: any): void { 8 | if (key === 'Fn::Cmd') 9 | { 10 | if (typeof val !== 'string') { 11 | if (!context.finalPass) { return; } 12 | throw new OrgFormationError(`Fn::Cmd expression expects a string as value. Found ${typeof val}`); 13 | } 14 | 15 | try { 16 | const process = execSync(val); 17 | const stdout = process.toString().trimRight(); 18 | resourceParent[resourceKey] = stdout; 19 | } catch (error) { 20 | throw new OrgFormationError(`Fn::Cmd expression failed: ${error}`); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/core/cfn-functions/cfn-json-string.ts: -------------------------------------------------------------------------------- 1 | import { ICfnFunctionContext } from './cfn-functions'; 2 | 3 | export class CfnJsonString { 4 | 5 | static resolve(context: ICfnFunctionContext, resource: any, resourceParent: any, resourceKey: string, key: string, val: any): void { 6 | if (key === 'Fn::JsonString') { 7 | 8 | let obj = val; 9 | let prettyPrint = false; 10 | if (Array.isArray(obj)) { 11 | if (obj.length === 2 && obj[1] === 'pretty-print') { 12 | prettyPrint = true; 13 | } 14 | obj = obj[0]; 15 | } 16 | 17 | const result = CfnJsonString.toJsonString(obj, prettyPrint); 18 | resourceParent[resourceKey] = result; 19 | } 20 | } 21 | 22 | private static toJsonString(val: any, prettyPrint: boolean): string { 23 | let result = ''; 24 | if (typeof val === 'string') { 25 | const parsed = JSON.parse(val); 26 | result = JSON.stringify(parsed, null, prettyPrint? 2 : 0); 27 | } else { 28 | result = JSON.stringify(val, null, prettyPrint? 2 : 0); 29 | } 30 | return result; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/core/cfn-functions/cfn-md5.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import md5 from 'md5'; 3 | import { ICfnFunctionContext } from './cfn-functions'; 4 | import { Md5Util } from '~util/md5-util'; 5 | 6 | export class CfnMD5 { 7 | 8 | static resolve(context: ICfnFunctionContext, resource: any, resourceParent: any, resourceKey: string, key: string, val: any): void { 9 | if (key === 'Fn::MD5') 10 | { 11 | resourceParent[resourceKey] = CfnMD5.calcMd5(val); 12 | } 13 | else if (key === 'Fn::MD5Dir' || key === 'Fn::MD5File') 14 | { 15 | const dir = path.dirname(context.filePath); 16 | const resolvedFilePath = path.resolve(dir, val); 17 | resourceParent[resourceKey] = Md5Util.Md5OfPath(resolvedFilePath); 18 | } 19 | } 20 | 21 | static calcMd5(contents: any): string { 22 | if (typeof contents === 'string') { 23 | return md5(contents); 24 | } else { 25 | return md5(JSON.stringify(contents)); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/core/cfn-functions/cfn-merge.ts: -------------------------------------------------------------------------------- 1 | import { ICfnFunctionContext } from './cfn-functions'; 2 | 3 | export class CfnMerge { 4 | 5 | static resolve(context: ICfnFunctionContext, resource: any, resourceParent: any, resourceKey: string, key: string, val: any): void { 6 | if (key === '<<' && typeof val === 'object') { 7 | const declaredMap = { ...resourceParent[resourceKey] }; 8 | delete declaredMap['<<']; 9 | resourceParent[resourceKey] = {...val, ...declaredMap}; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/core/cfn-functions/cfn-read-file.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'fs'; 2 | import path from 'path'; 3 | import { ICfnFunctionContext } from './cfn-functions'; 4 | import { OrgFormationError } from '~org-formation-error'; 5 | 6 | export class CfnReadFile { 7 | 8 | static resolve(context: ICfnFunctionContext, resource: any, resourceParent: any, resourceKey: string, key: string, val: any): void { 9 | if (key === 'Fn::ReadFile') 10 | { 11 | if (typeof val !== 'string') { 12 | if (!context.finalPass) { return; } 13 | throw new OrgFormationError(`Fn::ReadFile expression expects a string as value. Found ${typeof val}`); 14 | } 15 | 16 | const resolved = CfnReadFile.readFile(context.filePath, val); 17 | resourceParent[resourceKey] = resolved; 18 | } 19 | } 20 | 21 | static readFile(contextPath: string, filePath: string): string { 22 | const dir = path.dirname(contextPath); 23 | const resolvedFilePath = path.resolve(dir, filePath); 24 | return readFileSync(resolvedFilePath).toString('utf-8'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/core/cfn-functions/cfn-sub.ts: -------------------------------------------------------------------------------- 1 | import { ICfnFunctionContext } from './cfn-functions'; 2 | import { CfnExpressionResolver } from '~core/cfn-expression-resolver'; 3 | import { OrgFormationError } from '~org-formation-error'; 4 | 5 | export class CfnSub { 6 | 7 | static resolve(context: ICfnFunctionContext, resource: any, resourceParent: any, resourceKey: string, key: string, val: any): void { 8 | if (key === 'Fn::Sub' && typeof val === 'object' && Array.isArray(val) && val.length === 2) { 9 | if (val.length !== 2) { 10 | throw new OrgFormationError('Complex Fn::Sub expression expected to have 2 array elements (expression and object with parameters)'); 11 | } 12 | 13 | const resolver = new CfnExpressionResolver(); 14 | const parameters = Object.entries(val[1]); 15 | for (const param of parameters) { 16 | resolver.addParameter(param[0], param[1] as string); 17 | } 18 | 19 | const value = resolver.resolveFirstPass({ 'Fn::Sub': val[0] }); 20 | resourceParent[resourceKey] = value; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/core/default-task-runner.ts: -------------------------------------------------------------------------------- 1 | import { OrgFormationError } from '../org-formation-error'; 2 | import { GenericTaskRunner, ITaskRunnerDelegates } from '~core/generic-task-runner'; 3 | import { IGenericTask } from '~plugin/plugin-binder'; 4 | 5 | export class DefaultTaskRunner { 6 | 7 | public static async RunTasks(tasks: IGenericTask[], logicalName: string, logVerbose: boolean, maxConcurrentTasks: number, failedTasksTolerance: number): Promise { 8 | if (maxConcurrentTasks === undefined) { 9 | throw new OrgFormationError('maxConcurrentTasks must not be undefined'); 10 | } 11 | if (failedTasksTolerance === undefined) { 12 | throw new OrgFormationError('failedTasksTolerance must not be undefined'); 13 | } 14 | const delegate: ITaskRunnerDelegates = { 15 | getName: task => `Workload ${task.logicalName} in ${task.accountId}/${task.region}`, 16 | getVerb: task => `${task.action === 'Delete' ? 'delete' : 'update'}`, 17 | maxConcurrentTasks, 18 | failedTasksTolerance, 19 | logVerbose, 20 | }; 21 | await GenericTaskRunner.RunTasks(tasks, delegate); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/org-formation-error.ts: -------------------------------------------------------------------------------- 1 | export class OrgFormationError extends Error { 2 | constructor(message: string, public readonly code: ErrorCode = ErrorCode.Unknown) { 3 | super(message); 4 | } 5 | 6 | 7 | } 8 | 9 | 10 | export enum ErrorCode { 11 | Unknown, 12 | FailureToRemove 13 | } 14 | -------------------------------------------------------------------------------- /src/parser/model/index.ts: -------------------------------------------------------------------------------- 1 | export * from './account-resource'; 2 | export * from './cloudformation-resource'; 3 | export * from './master-account-resource'; 4 | export * from './organization-bindings-section'; 5 | export * from './organization-root-resource'; 6 | export * from './organization-section'; 7 | export * from './organizational-unit-resource'; 8 | export * from './password-policy-resource'; 9 | export * from './resource-types'; 10 | export * from './resource'; 11 | export * from './resources-section'; 12 | export * from './service-control-policy-resource'; 13 | -------------------------------------------------------------------------------- /src/parser/model/master-account-resource.ts: -------------------------------------------------------------------------------- 1 | import { OrgFormationError } from '../../org-formation-error'; 2 | import { IResource, TemplateRoot } from '../parser'; 3 | import { AccountResource } from './account-resource'; 4 | 5 | export class MasterAccountResource extends AccountResource { 6 | 7 | constructor(root: TemplateRoot, id: string, resource: IResource) { 8 | super(root, id, resource); 9 | if (this.supportLevel) { 10 | throw new OrgFormationError('specifying SupportLevel on a MasterAccount resource is not supported, a support level must be subscribed to in the console.'); 11 | } 12 | if (!this.accountId) { 13 | throw new OrgFormationError(`AccountId is missing on MasterAccount ${id}`); 14 | } 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/parser/model/resource-types.ts: -------------------------------------------------------------------------------- 1 | 2 | export enum OrgResourceTypes { 3 | ServiceControlPolicy = 'OC::ORG::ServiceControlPolicy', 4 | OrganizationalUnit = 'OC::ORG::OrganizationalUnit', 5 | Account = 'OC::ORG::Account', 6 | MasterAccount = 'OC::ORG::MasterAccount', 7 | OrganizationRoot = 'OC::ORG::OrganizationRoot', 8 | PasswordPolicy = 'OC::ORG::PasswordPolicy', 9 | } 10 | -------------------------------------------------------------------------------- /src/plugin/plugin-util.ts: -------------------------------------------------------------------------------- 1 | import { existsSync } from 'fs'; 2 | import path from 'path'; 3 | 4 | export class PluginUtil { 5 | static PrependNpmInstall(workloadPath: string, command: string): string { 6 | const hasPackageLock = existsSync(path.resolve(workloadPath, 'package-lock.json')); 7 | if (hasPackageLock) { 8 | return 'npm ci && ' + command; 9 | } else { 10 | return 'npm i && ' + command; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/util/aws-config.ts: -------------------------------------------------------------------------------- 1 | import { ClientCredentialsConfig } from './aws-types'; 2 | 3 | export class AWSConfig { 4 | credentials?: ClientCredentialsConfig; 5 | region?: string; 6 | 7 | private static sharedInstance: AWSConfig | null = null; 8 | 9 | private constructor() { 10 | this.credentials = undefined; 11 | this.region = undefined; 12 | } 13 | 14 | static shared(): AWSConfig { 15 | if(AWSConfig.sharedInstance === null) { 16 | AWSConfig.sharedInstance = new AWSConfig(); 17 | } 18 | return AWSConfig.sharedInstance; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/util/aws-types.ts: -------------------------------------------------------------------------------- 1 | import { AwsCredentialIdentity, Provider } from '@smithy/types'; 2 | 3 | export type ClientCredentialsConfig = AwsCredentialIdentity | Provider; 4 | 5 | export interface DefaultClientConfig { 6 | credentials?: ClientCredentialsConfig; 7 | region?: string; 8 | stsRegionalEndpoints?: 'legacy' | 'regional'; 9 | } 10 | -------------------------------------------------------------------------------- /src/util/credentials-provider-custom-env.ts: -------------------------------------------------------------------------------- 1 | import { CredentialsProviderError } from '@smithy/property-provider'; 2 | import { AwsCredentialIdentity, AwsCredentialIdentityProvider } from '@smithy/types'; 3 | 4 | const ENV_KEY = '_ACCESS_KEY_ID'; 5 | const ENV_SECRET = '_SECRET_ACCESS_KEY'; 6 | const ENV_SESSION = '_SESSION_TOKEN'; 7 | const ENV_EXPIRATION = '_CREDENTIAL_EXPIRATION'; 8 | 9 | export function fromCustomEnv(prefix: string): AwsCredentialIdentityProvider { 10 | return async () => { 11 | const accessKeyId = process.env[prefix + ENV_KEY]; 12 | const secretAccessKey = process.env[prefix + ENV_SECRET]; 13 | const sessionToken = process.env[prefix + ENV_SESSION]; 14 | const expiry = process.env[prefix + ENV_EXPIRATION]; 15 | if (accessKeyId && secretAccessKey) { 16 | const identity: AwsCredentialIdentity= { 17 | accessKeyId, 18 | secretAccessKey, 19 | ...(sessionToken && { sessionToken }), 20 | ...(expiry && { expiration: new Date(expiry) }), 21 | }; 22 | return identity; 23 | } 24 | throw new CredentialsProviderError('Unable to find environment variable credentials.', true); 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /src/util/credentials-provider-partition.ts: -------------------------------------------------------------------------------- 1 | import { CredentialsProviderError } from '@smithy/property-provider'; 2 | import { AwsCredentialIdentity, AwsCredentialIdentityProvider } from '@smithy/types'; 3 | 4 | export function partitionFromEnv(isPartition: boolean): AwsCredentialIdentityProvider { 5 | return async () => { 6 | const accessKeyId = process.env.GOV_AWS_ACCESS_KEY_ID; 7 | const secretAccessKey = process.env.GOV_AWS_SECRET_ACCESS_KEY; 8 | 9 | if (isPartition && accessKeyId && secretAccessKey) { 10 | const identity: AwsCredentialIdentity = { 11 | accessKeyId, 12 | secretAccessKey, 13 | }; 14 | return identity; 15 | } 16 | throw new CredentialsProviderError('GOV_AWS_ACCESS_KEY_ID or GOV_AWS_SECRET_ACCESS_KEY missing', true); 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /src/yaml-cfn/nunjucks-parse-includes.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'fs'; 2 | import path from 'path'; 3 | import { nunjucksParse } from '.'; 4 | 5 | const include = /!Include\s+('|")?([^'"\s]*)('|")?/g; 6 | export const nunjucksParseContentWithIncludes = (contents: string, directory: string, filename: string, templatingContext: any): any => { 7 | const replacedContents = contents.replace(include, (_, __, includedRelativeFilePath) => { 8 | 9 | const resolvedFilePath = path.resolve(directory, includedRelativeFilePath); 10 | const included = nunjucksParseWithIncludes(resolvedFilePath, templatingContext); 11 | return JSON.stringify(included); 12 | }); 13 | 14 | const parsed = nunjucksParse(replacedContents, filename, templatingContext); 15 | return parsed; 16 | }; 17 | 18 | export const nunjucksParseWithIncludes = (filePath: string, templatingContext: any): any => { 19 | const buffer = readFileSync(filePath); 20 | const contents = buffer.toString('utf-8'); 21 | const dir = path.dirname(filePath); 22 | const filename = path.basename(filePath); 23 | return nunjucksParseContentWithIncludes(contents, dir, filename, templatingContext); 24 | }; 25 | -------------------------------------------------------------------------------- /src/yaml-cfn/yaml-parse-includes.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'fs'; 2 | import path from 'path'; 3 | import { yamlParse } from '.'; 4 | 5 | const include = /!Include\s+('|")?([^'"\s]*)('|")?/g; 6 | export const yamlParseContentWithIncludes = (contents: string, directory: string): any => { 7 | const replacedContents = contents.replace(include, (_, __, includedRelativeFilePath) => { 8 | 9 | const resolvedFilePath = path.resolve(directory, includedRelativeFilePath); 10 | const included = yamlParseWithIncludes(resolvedFilePath); 11 | return JSON.stringify(included); 12 | }); 13 | 14 | const parsed = yamlParse(replacedContents); 15 | return parsed; 16 | }; 17 | 18 | export const yamlParseWithIncludes = (filePath: string): any => { 19 | const buffer = readFileSync(filePath); 20 | const contents = buffer.toString('utf-8'); 21 | const dir = path.dirname(filePath); 22 | return yamlParseContentWithIncludes(contents, dir); 23 | }; 24 | -------------------------------------------------------------------------------- /test/integration-tests/cli-tests/cli-version.test.ts: -------------------------------------------------------------------------------- 1 | import { spawnSync } from 'child_process'; 2 | 3 | describe('when calling org-formation --version', () => { 4 | let stdout: string; 5 | 6 | beforeEach(() => { 7 | const response = spawnSync('npx', ['ts-node', 'cli', '--version']); 8 | stdout = response.stdout.toString(); 9 | }); 10 | 11 | test('returns version to stdout', () => { 12 | expect(stdout).toBeDefined(); 13 | 14 | const pjson = require('../../../package.json'); 15 | expect(stdout).toBe(pjson.version + '\n'); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/integration-tests/cli-tests/failed-tasks.test.ts: -------------------------------------------------------------------------------- 1 | import { spawnSync, SpawnSyncReturns } from 'child_process'; 2 | import { existsSync, writeFileSync } from 'fs'; 3 | import { ConsoleUtil } from '~util/console-util'; 4 | 5 | describe('when org-formation perform-tasks fails', () => { 6 | let response: SpawnSyncReturns; 7 | 8 | beforeAll(() => { 9 | response = spawnSync('npx', ['ts-node', 'cli', 'perform-tasks', './test/integration-tests/resources/scenario-task-that-fails/organization-tasks.yml', '--no-color', '--profile', 'org-formation-test-v2', '--print-stack']); 10 | }); 11 | 12 | test('exit with statuscode 1', () => { 13 | ConsoleUtil.LogWarning('test does not work on CI'); 14 | // expect(response).toBeDefined(); 15 | // expect(response.status).toBe(1); 16 | }); 17 | 18 | test('error is written to stderr', () =>{ 19 | ConsoleUtil.LogWarning('test does not work on CI'); 20 | // const error = response.stderr.toString(); 21 | // expect(error).toContain('Template format error'); 22 | // expect(error).toContain('XX::S3::Bucket'); 23 | // expect(error).toContain('Stack invalid-template in account'); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-anchors-aliases/1-deploy.yml: -------------------------------------------------------------------------------- 1 | 2 | Definitions: 3 | - &skiptrue 4 | Skip: true 5 | - &defaultbinding 6 | DefaultOrganizationBindingRegion: eu-west-1 7 | DefaultOrganizationBinding: 8 | IncludeMasterAccount: true 9 | 10 | OrganizationUpdate: 11 | Type: update-organization 12 | Template: ./organization.yml 13 | <<: *skiptrue 14 | 15 | AnchorsAndAliases: 16 | Type: update-stacks 17 | StackName: anchors-and-aliases 18 | Template: ./buckets.yml 19 | <<: *defaultbinding -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-anchors-aliases/9-cleanup.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-anchors-aliases/buckets.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Definitions: 4 | - &bucket 5 | Type: AWS::S3::Bucket 6 | 7 | Resources: 8 | Bucket: 9 | <<: *bucket 10 | 11 | Outputs: 12 | BucketName: 13 | Value: !GetAtt Bucket.Arn 14 | Export: 15 | Name: BucketArn -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-anchors-aliases/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Definitions: 5 | - &defaultTags 6 | Department: Platform 7 | Project: Infrastructure 8 | CloudwatchCloudTrailLogRetentionPeriod: 90 9 | 10 | Organization: 11 | MasterAccount: 12 | Type: OC::ORG::MasterAccount 13 | Properties: 14 | AccountName: Organizational Master Account 15 | AccountId: '102625093955' 16 | Tags: 17 | <<: *defaultTags 18 | Project: Other 19 | 20 | 21 | 22 | AccountA: 23 | Type: OC::ORG::Account 24 | Properties: 25 | RootEmail: account+a@olafconijn.awsapps.com 26 | AccountName: Account A 27 | Tags: 28 | <<: *defaultTags 29 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-annotate-organization/1-deploy.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: annotate-organization 4 | AccountMapping: 5 | "Security Account": 152091636325 6 | 7 | AnchorsAndAliases: 8 | Type: update-stacks 9 | DefaultOrganizationBinding: 10 | Account: !Ref Security Account 11 | Region: us-east-1 12 | StackName: anchors-and-aliases 13 | Template: ./buckets.yml -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-annotate-organization/buckets.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Definitions: 4 | - &bucket 5 | Type: AWS::S3::Bucket 6 | 7 | Resources: 8 | Bucket: 9 | <<: *bucket 10 | 11 | Outputs: 12 | BucketName: 13 | Value: !GetAtt Bucket.Arn 14 | Export: 15 | Name: BucketArn -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-annotate-organization/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Definitions: 5 | - &defaultTags 6 | Department: Platform 7 | Project: Infrastructure 8 | CloudwatchCloudTrailLogRetentionPeriod: 90 9 | 10 | Organization: 11 | MasterAccount: 12 | Type: OC::ORG::MasterAccount 13 | Properties: 14 | AccountName: Organizational Master Account 15 | AccountId: '102625093955' 16 | Tags: 17 | <<: *defaultTags 18 | Project: Other 19 | 20 | 21 | 22 | AccountA: 23 | Type: OC::ORG::Account 24 | Properties: 25 | RootEmail: account+a@olafconijn.awsapps.com 26 | AccountName: Account A 27 | Tags: 28 | <<: *defaultTags 29 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-attach-account/1-init-organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-attach-account/2-attach-organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | 6 | MasterAccount: 7 | Type: OC::ORG::MasterAccount 8 | Properties: 9 | AccountName: Organizational Master Account 10 | AccountId: '102625093955' 11 | 12 | AccountA: 13 | Type: OC::ORG::Account 14 | Properties: 15 | RootEmail: account+a@olafconijn.awsapps.com 16 | AccountName: Account A -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-attach-account/3-detach-organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-attach-account/state.json: -------------------------------------------------------------------------------- 1 | { 2 | "masterAccountId": "102625093955", 3 | "bindings": { 4 | "OC::ORG::MasterAccount": { 5 | "MasterAccount": { 6 | "type": "OC::ORG::MasterAccount", 7 | "logicalId": "MasterAccount", 8 | "physicalId": "102625093955", 9 | "lastCommittedHash": "281db6b2c685159c8f11b2c8289abd7b" 10 | } 11 | }, 12 | "OC::ORG::OrganizationRoot": { 13 | "OrganizationRoot": { 14 | "type": "OC::ORG::OrganizationRoot", 15 | "logicalId": "OrganizationRoot", 16 | "physicalId": "r-kvte", 17 | "lastCommittedHash": "6be66ccf6b2a5417439fec93c294f165" 18 | } 19 | }, 20 | "OC::ORG::OrganizationalUnit": {} 21 | }, 22 | "stacks": {}, 23 | "values": { 24 | "organization.template.hash": "1f7c06baf83ee72e843890bce9790d2f" 25 | }, 26 | "previousTemplate": "{\"AWSTemplateFormatVersion\":\"2010-09-09-OC\",\"Description\":\"default template generated for organization with master account 102625093955\",\"Organization\":{\"MasterAccount\":{\"Type\":\"OC::ORG::MasterAccount\",\"Properties\":{\"AccountName\":\"Olaf Conijn\",\"AccountId\":\"102625093955\"}},\"OrganizationRoot\":{\"Type\":\"OC::ORG::OrganizationRoot\",\"Properties\":null}}}" 27 | } -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-no-region/1-deploy-cdk-workload-1target.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | CdkWorkload: 8 | Type: update-cdk 9 | Path: ./workload/ 10 | RunNpmInstall: true 11 | OrganizationBinding: 12 | Account: !Ref AccountA 13 | Region: eu-central-1 14 | MaxConcurrentTasks: 1 15 | FailedTaskTolerance: 0 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-no-region/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-no-region/workload/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node index.ts" 3 | } 4 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-no-region/workload/index.ts: -------------------------------------------------------------------------------- 1 | import { App, Construct, StackProps, Stack } from '@aws-cdk/core'; 2 | import s3 = require('@aws-cdk/aws-s3'); 3 | import sns = require('@aws-cdk/aws-sns'); 4 | 5 | class MyStack extends Stack { 6 | constructor(scope: Construct, id: string, props?: StackProps) { 7 | super(scope, id, props); 8 | 9 | new sns.Topic(this, 'MyTopic'); 10 | new s3.Bucket(this, 'MyBucket'); 11 | } 12 | } 13 | 14 | const app = new App(); 15 | new MyStack(app, 'MyStack'); 16 | app.synth(); -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-no-region/workload/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "custom-logical-names", 3 | "version": "0.1.0", 4 | "bin": { 5 | "custom-logical-names": "bin/custom-logical-names.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "cdk": "cdk" 11 | }, 12 | "devDependencies": { 13 | "aws-cdk": "*", 14 | "ts-node": "^8.1.0", 15 | "typescript": "~3.7.2" 16 | }, 17 | "dependencies": { 18 | "@aws-cdk/aws-s3": "*", 19 | "@aws-cdk/aws-sns": "*", 20 | "@aws-cdk/core": "*", 21 | "source-map-support": "^0.5.9" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-no-region/workload/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target":"ES2018", 4 | "module": "commonjs", 5 | "lib": ["es2016", "es2017.object", "es2017.string"], 6 | "declaration": true, 7 | "strict": true, 8 | "noImplicitAny": true, 9 | "strictNullChecks": true, 10 | "noImplicitThis": true, 11 | "alwaysStrict": true, 12 | "noUnusedLocals": false, 13 | "noUnusedParameters": false, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": false, 16 | "inlineSourceMap": true, 17 | "inlineSources": true, 18 | "experimentalDecorators": true, 19 | "strictPropertyInitialization":false, 20 | "typeRoots": ["./node_modules/@types"] 21 | }, 22 | "exclude": ["cdk.out"] 23 | } 24 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-task/1-deploy-cdk-workload-2targets.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | CdkWorkload: 8 | Type: update-cdk 9 | Path: ./workload/ 10 | RunNpmInstall: true 11 | RunNpmBuild: true 12 | OrganizationBinding: 13 | IncludeMasterAccount: true 14 | Account: !Ref AccountA 15 | Region: eu-central-1 16 | MaxConcurrentTasks: 1 17 | FailedTaskTolerance: 0 18 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-task/2-update-cdk-workload-with-parameters.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | CdkWorkload: 8 | Type: update-cdk 9 | Path: ./workload/ 10 | RunNpmInstall: true 11 | OrganizationBinding: 12 | IncludeMasterAccount: true 13 | Account: !Ref AccountA 14 | Region: eu-central-1 15 | Parameters: 16 | param1: !Sub 'sub expression ${AWS::AccountId}' 17 | param2: !GetAtt AccountA.AccountName 18 | param3: !GetAtt CurrentAccount.Tags.Tag 19 | MaxConcurrentTasks: 1 20 | FailedTaskTolerance: 0 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-task/3-deploy-cdk-workload-1target.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | CdkWorkload: 8 | Type: update-cdk 9 | Path: ./workload/ 10 | RunNpmInstall: true 11 | Parameters: 12 | param1: !Sub 'sub expression ${AWS::AccountId}' 13 | param2: !GetAtt AccountA.AccountName 14 | param3: !GetAtt CurrentAccount.Tags.Tag 15 | OrganizationBinding: 16 | Account: !Ref AccountA 17 | Region: eu-central-1 18 | MaxConcurrentTasks: 1 19 | FailedTaskTolerance: 0 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-task/4-remove-cdk-workload-task.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-task/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | Tags: 11 | Tag: TagValue1 12 | 13 | AccountA: 14 | Type: OC::ORG::Account 15 | Properties: 16 | RootEmail: account+a@olafconijn.awsapps.com 17 | AccountName: Account A 18 | Tags: 19 | Tag: TagValue2 20 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-task/workload/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node index.ts" 3 | } 4 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-task/workload/cdk.out/MyStack.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "MyTopic86869434": { 4 | "Type": "AWS::SNS::Topic", 5 | "Metadata": { 6 | "aws:cdk:path": "MyStack/MyTopic/Resource" 7 | } 8 | }, 9 | "MyBucketF68F3FF0": { 10 | "Type": "AWS::S3::Bucket", 11 | "UpdateReplacePolicy": "Retain", 12 | "DeletionPolicy": "Retain", 13 | "Metadata": { 14 | "aws:cdk:path": "MyStack/MyBucket/Resource" 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-task/workload/cdk.out/cdk.out: -------------------------------------------------------------------------------- 1 | {"version":"1.33.0"} -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-task/workload/index.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-task/workload/index.ts: -------------------------------------------------------------------------------- 1 | import { App, Construct, StackProps, Stack } from '@aws-cdk/core'; 2 | import s3 = require('@aws-cdk/aws-s3'); 3 | import sns = require('@aws-cdk/aws-sns'); 4 | 5 | class MyStack extends Stack { 6 | constructor(scope: Construct, id: string, props?: StackProps) { 7 | super(scope, id, props); 8 | 9 | new sns.Topic(this, 'MyTopic'); 10 | new s3.Bucket(this, 'MyBucket'); 11 | } 12 | } 13 | 14 | const app = new App(); 15 | new MyStack(app, 'MyStack'); 16 | app.synth(); -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-task/workload/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "custom-logical-names", 3 | "version": "0.1.0", 4 | "bin": { 5 | "custom-logical-names": "bin/custom-logical-names.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "cdk": "cdk" 11 | }, 12 | "devDependencies": { 13 | "aws-cdk": "*", 14 | "ts-node": "^8.1.0", 15 | "typescript": "~3.7.2" 16 | }, 17 | "dependencies": { 18 | "@aws-cdk/aws-s3": "*", 19 | "@aws-cdk/aws-sns": "*", 20 | "@aws-cdk/core": "*", 21 | "source-map-support": "^0.5.9" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cdk-task/workload/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target":"ES2018", 4 | "module": "commonjs", 5 | "lib": ["es2016", "es2017.object", "es2017.string"], 6 | "declaration": true, 7 | "strict": true, 8 | "noImplicitAny": true, 9 | "strictNullChecks": true, 10 | "noImplicitThis": true, 11 | "alwaysStrict": true, 12 | "noUnusedLocals": false, 13 | "noUnusedParameters": false, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": false, 16 | "inlineSourceMap": true, 17 | "inlineSources": true, 18 | "experimentalDecorators": true, 19 | "strictPropertyInitialization":false, 20 | "typeRoots": ["./node_modules/@types"] 21 | }, 22 | "exclude": ["cdk.out"] 23 | } 24 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cfn-parameter-expressions/2-cleanup-update-stacks-with-param-expressions.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cfn-parameter-expressions/bucket.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | Bucket: 5 | Type: AWS::S3::Bucket 6 | 7 | Outputs: 8 | BucketName: 9 | Value: !GetAtt Bucket.Arn 10 | Export: 11 | Name: BucketArn -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cfn-parameter-expressions/file.txt: -------------------------------------------------------------------------------- 1 | contents of file -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cfn-parameter-expressions/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | 6 | OrganizationRoot: 7 | Type: OC::ORG::OrganizationRoot 8 | 9 | MasterAccount: 10 | Type: OC::ORG::MasterAccount 11 | Properties: 12 | AccountName: Organizational Master Account 13 | AccountId: '102625093955' 14 | Tags: 15 | Tag: tag-value 16 | AccountA: 17 | Type: OC::ORG::Account 18 | Properties: 19 | RootEmail: account+a@olafconijn.awsapps.com 20 | AccountName: Account A 21 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cfn-parameter-expressions/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "val" 3 | } -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cleanup-stacks/organization-tasks-buckets.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | 8 | CfnTemplate: 9 | Type: update-stacks 10 | Template: ./templates/buckets.yml 11 | StackName: scenario-cleanup-buckets 12 | MaxConcurrentStacks: 10 13 | 14 | CfnCustomRole: 15 | Type: update-stacks 16 | Template: ./templates/custom-role.yml 17 | StackName: custom-role 18 | MaxConcurrentStacks: 10 19 | 20 | CfnCustomRoleBuckets: 21 | Type: update-stacks 22 | DependsOn: CfnCustomRole 23 | TaskRoleName: CustomRole 24 | Template: ./templates/buckets.yml 25 | StackName: buckets-using-custom-role 26 | MaxConcurrentStacks: 10 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cleanup-stacks/organization-tasks-empty.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cleanup-stacks/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cleanup-stacks/state.json: -------------------------------------------------------------------------------- 1 | { 2 | "masterAccountId": "102625093955", 3 | "bindings": { 4 | "OC::ORG::MasterAccount": { 5 | "MasterAccount": { 6 | "type": "OC::ORG::MasterAccount", 7 | "logicalId": "MasterAccount", 8 | "physicalId": "102625093955", 9 | "lastCommittedHash": "281db6b2c685159c8f11b2c8289abd7b" 10 | } 11 | }, 12 | "OC::ORG::OrganizationRoot": { 13 | "OrganizationRoot": { 14 | "type": "OC::ORG::OrganizationRoot", 15 | "logicalId": "OrganizationRoot", 16 | "physicalId": "r-kvte", 17 | "lastCommittedHash": "6be66ccf6b2a5417439fec93c294f165" 18 | } 19 | }, 20 | "OC::ORG::OrganizationalUnit": {} 21 | }, 22 | "stacks": {}, 23 | "values": { 24 | "organization.template.hash": "1f7c06baf83ee72e843890bce9790d2f", 25 | "state-version": "2" 26 | }, 27 | "previousTemplate": "{\"AWSTemplateFormatVersion\":\"2010-09-09-OC\",\"Description\":\"default template generated for organization with master account 102625093955\",\"Organization\":{\"MasterAccount\":{\"Type\":\"OC::ORG::MasterAccount\",\"Properties\":{\"AccountName\":\"Olaf Conijn\",\"AccountId\":\"102625093955\"}},\"OrganizationRoot\":{\"Type\":\"OC::ORG::OrganizationRoot\",\"Properties\":null}}}" 28 | } -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cleanup-stacks/templates/buckets.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | Bucket: 5 | OrganizationBinding: 6 | Region: eu-west-1 7 | Account: '*' 8 | IncludeMasterAccount: true 9 | Type: AWS::S3::Bucket 10 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-cleanup-stacks/templates/custom-role.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | Role: 5 | Type: AWS::IAM::Role 6 | OrganizationBinding: 7 | Region: eu-west-1 8 | Account: '*' 9 | IncludeMasterAccount: true 10 | Properties: 11 | ManagedPolicyArns: 12 | - arn:aws:iam::aws:policy/AdministratorAccess 13 | RoleName: CustomRole 14 | AssumeRolePolicyDocument: 15 | Version: 2012-10-17 16 | Statement: 17 | - Effect: Allow 18 | Action: sts:AssumeRole 19 | Principal: 20 | AWS: !Ref MasterAccount 21 | 22 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-copy-to-s3/files/file.txt: -------------------------------------------------------------------------------- 1 | 0.006778610259068785 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-copy-to-s3/files/something-else.txt: -------------------------------------------------------------------------------- 1 | this is different -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-copy-to-s3/files/template.njk: -------------------------------------------------------------------------------- 1 | number is: {{ number }} 2 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-copy-to-s3/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-copy-to-s3/template-fixed-export.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | 3 | Resources: 4 | 5 | RandomResource: 6 | Type: AWS::S3::Bucket 7 | 8 | Outputs: 9 | 10 | TestS3BucketNameOutput: 11 | Description: A fixed value used for testing 12 | Value: org-formation-integration-test 13 | Export: 14 | Name: TestS3BucketName -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-copyvalue-buildrole/0-tasks.yml: -------------------------------------------------------------------------------- 1 | 2 | Parameters: 3 | 4 | stackPrefix: 5 | Description: 6 | Type: String 7 | Default: scenario-copyvalue-buildrole 8 | 9 | region1: 10 | Type: String 11 | Default: eu-west-1 12 | 13 | region2: 14 | Type: String 15 | Default: eu-central-1 16 | 17 | buildTaskRoleName: 18 | Type: String 19 | Default: !GetAtt CurrentAccount.BuildAccessRoleName 20 | 21 | OrganizationUpdate: 22 | Type: update-organization 23 | Template: ./organization.yml 24 | TaskRoleName: 'OrganizationFormationBuildRole' 25 | 26 | BucketOne: 27 | TaskRoleName: !Ref buildTaskRoleName 28 | DependsOn: 29 | - OrganizationUpdate 30 | Type: update-stacks 31 | Template: ./bucket.yml 32 | StackName: !Sub ${stackPrefix}-source 33 | DefaultOrganizationBindingRegion: !Ref region1 34 | DefaultOrganizationBinding: 35 | Account: !Ref AccountB 36 | 37 | DependentBucket: 38 | TaskRoleName: !Ref buildTaskRoleName 39 | DependsOn: 40 | - BucketOne 41 | Type: update-stacks 42 | Template: ./bucket2.yml 43 | StackName: !Sub ${stackPrefix}-target 44 | DefaultOrganizationBindingRegion: !Ref region2 45 | DefaultOrganizationBinding: 46 | IncludeMasterAccount: true 47 | Parameters: 48 | bucketName: !CopyValue [ !Sub "${stackPrefix}-source-bucket-name", !Ref AccountB, !Ref region1 ] 49 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-copyvalue-buildrole/9-cleanup-organization.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Template: ./organization.yml 5 | TaskRoleName: 'OrganizationFormationBuildRole' 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-copyvalue-buildrole/bucket.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | 3 | Resources: 4 | Bucket: 5 | Type: AWS::S3::Bucket 6 | Properties: 7 | BucketName: !Sub 8 | - "scenario-copyvalue-buildrole-${fourPseudoRandom}" 9 | - fourPseudoRandom: !Select [3, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]] 10 | 11 | Outputs: 12 | 13 | BucketName: 14 | Description: The Bucket name 15 | Value: !Ref Bucket 16 | Export: 17 | Name: !Sub "${AWS::StackName}-bucket-name" -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-copyvalue-buildrole/bucket2.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | 3 | Parameters: 4 | bucketName: 5 | Type: String 6 | 7 | Resources: 8 | Bucket: 9 | Type: AWS::S3::Bucket 10 | Properties: 11 | BucketName: !Sub "${bucketName}-dependent" 12 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-copyvalue-buildrole/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | OrganizationRoot: 6 | Type: OC::ORG::OrganizationRoot 7 | Properties: 8 | DefaultOrganizationAccessRoleName: OrganizationAccountAccessRole 9 | DefaultBuildAccessRoleName: OrganizationFormationBuildRole 10 | 11 | MasterAccount: 12 | Type: OC::ORG::MasterAccount 13 | Properties: 14 | AccountName: Organizational Master Account 15 | AccountId: '102625093955' 16 | 17 | OrganizationBuildAccount: 18 | Type: OC::ORG::Account 19 | Properties: 20 | AccountName: Account A 21 | AccountId: '340381375986' 22 | RootEmail: account+a@olafconijn.awsapps.com 23 | 24 | AccountB: 25 | Type: OC::ORG::Account 26 | Properties: 27 | AccountName: Account B 28 | AccountId: '362239514602' 29 | RootEmail: account+b@olafconijn.awsapps.com 30 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-create-account/0-update-organization.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | OrganizationUpdate: 4 | Type: update-organization 5 | Template: ./organization.yml 6 | TaskRoleName: 'OrganizationFormationBuildRole' 7 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-create-account/1-update-organization.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | OrganizationUpdate: 4 | Type: update-organization 5 | Template: ./organization-2.yml 6 | TaskRoleName: 'OrganizationFormationBuildRole' 7 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-create-account/9-cleanup-organization.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Template: ./organization.yml 5 | TaskRoleName: 'OrganizationFormationBuildRole' 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-create-account/organization-2.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | OrganizationRoot: 6 | Type: OC::ORG::OrganizationRoot 7 | Properties: 8 | DefaultBuildAccessRoleName: OrganizationFormationBuildRole 9 | 10 | MasterAccount: 11 | Type: OC::ORG::MasterAccount 12 | Properties: 13 | AccountName: Organizational Master Account 14 | AccountId: '102625093955' 15 | 16 | OrganizationBuildAccount: 17 | Type: OC::ORG::Account 18 | Properties: 19 | AccountName: Account A 20 | AccountId: '340381375986' 21 | RootEmail: account+a@olafconijn.awsapps.com 22 | 23 | NewAccount: 24 | Type: OC::ORG::Account 25 | Properties: 26 | Alias: scenario-new-account 27 | AccountName: Scenario New Account 28 | RootEmail: account+scenario-new-account@olafconijn.awsapps.com 29 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-create-account/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | OrganizationRoot: 6 | Type: OC::ORG::OrganizationRoot 7 | Properties: 8 | DefaultBuildAccessRoleName: OrganizationFormationBuildRole 9 | 10 | MasterAccount: 11 | Type: OC::ORG::MasterAccount 12 | Properties: 13 | AccountName: Organizational Master Account 14 | AccountId: '102625093955' 15 | 16 | OrganizationBuildAccount: 17 | Type: OC::ORG::Account 18 | Properties: 19 | AccountName: Account A 20 | AccountId: '340381375986' 21 | RootEmail: account+a@olafconijn.awsapps.com 22 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-create-buckets/buckets.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Organization: !Include ./organization.yml 4 | 5 | Resources: 6 | Bucket: 7 | OrganizationBinding: 8 | Region: eu-west-1 9 | Account: '*' 10 | IncludeMasterAccount: true 11 | Type: AWS::S3::Bucket 12 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-create-buckets/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-delegated-build-account/9-cleanup-organization.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Template: ./organization.yml 5 | TaskRoleName: 'OrganizationFormationBuildRole' 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-delegated-build-account/bucket.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | Bucket: 5 | Type: AWS::S3::Bucket 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-delegated-build-account/build-role.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | 3 | Parameters: 4 | 5 | buildAccountId: 6 | Type: String 7 | 8 | Resources: 9 | Role: 10 | Type: AWS::IAM::Role 11 | Properties: 12 | ManagedPolicyArns: 13 | - arn:aws:iam::aws:policy/AdministratorAccess 14 | RoleName: OrganizationFormationBuildRole 15 | AssumeRolePolicyDocument: 16 | Version: 2012-10-17 17 | Statement: 18 | - Effect: Allow 19 | Action: sts:AssumeRole 20 | Principal: 21 | AWS: !Ref buildAccountId -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-detached-perform-tasks/9-cleanup.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/test/integration-tests/resources/scenario-detached-perform-tasks/9-cleanup.yml -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-detached-perform-tasks/bucket.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | Bucket: 5 | Type: AWS::S3::Bucket 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-detached-perform-tasks/build-role.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | 3 | Parameters: 4 | 5 | buildAccountId: 6 | Type: String 7 | 8 | Resources: 9 | Role: 10 | Type: AWS::IAM::Role 11 | Properties: 12 | ManagedPolicyArns: 13 | - arn:aws:iam::aws:policy/AdministratorAccess 14 | RoleName: OrganizationFormationBuildRole 15 | AssumeRolePolicyDocument: 16 | Version: 2012-10-17 17 | Statement: 18 | - Effect: Allow 19 | Action: sts:AssumeRole 20 | Principal: 21 | AWS: !Ref buildAccountId -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-functions-in-cfn/1-deploy-cfn-with-functions.yml: -------------------------------------------------------------------------------- 1 | OrganizationUpdate: 2 | Type: update-organization 3 | Skip: true 4 | Template: ./organization.yml 5 | 6 | LambdaUsingReadFile: 7 | Type: update-stacks 8 | StackName: lambda-using-read-file 9 | Template: ./lambda-using-read-file.yml 10 | DefaultOrganizationBindingRegion: eu-west-1 11 | DefaultOrganizationBinding: 12 | IncludeMasterAccount: true 13 | 14 | BucketPolicyInline1: 15 | Type: update-stacks 16 | StackName: bucket-with-policy1 17 | Template: ./bucket-with-policy1.yml 18 | DefaultOrganizationBindingRegion: eu-west-1 19 | DefaultOrganizationBinding: 20 | IncludeMasterAccount: true 21 | Parameters: 22 | currentAccount: !Ref CurrentAccount 23 | 24 | BucketPolicyInline2: 25 | Type: update-stacks 26 | StackName: bucket-with-policy2 27 | Template: ./bucket-with-policy2.yml 28 | DefaultOrganizationBindingRegion: eu-west-1 29 | DefaultOrganizationBinding: 30 | IncludeMasterAccount: true 31 | Parameters: 32 | currentAccount: !Ref CurrentAccount 33 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-functions-in-cfn/9-cleanup-cfn-with-functions.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-functions-in-cfn/bucket-with-policy1.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09-OC 2 | 3 | Parameters: 4 | currentAccount: 5 | Type: String 6 | 7 | Resources: 8 | Bucket: 9 | Type: AWS::S3::Bucket 10 | 11 | BucketPolicy: 12 | Type: AWS::S3::BucketPolicy 13 | Properties: 14 | Bucket: !Ref Bucket 15 | PolicyDocument: 16 | Fn::Sub: 17 | - !JsonString 18 | Version: 2012-10-17 19 | Statement: 20 | - Action: 21 | - "s3:GetObject" 22 | Effect: Allow 23 | Resource: "arn:aws:s3:::${bucket}/*" 24 | Principal: 25 | AWS: ${account} 26 | - bucket: !Ref Bucket 27 | account: !Ref currentAccount 28 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-functions-in-cfn/bucket-with-policy2.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | 3 | Parameters: 4 | currentAccount: 5 | Type: String 6 | 7 | Resources: 8 | Bucket: 9 | Type: AWS::S3::Bucket 10 | 11 | BucketPolicy: 12 | Type: AWS::S3::BucketPolicy 13 | Properties: 14 | Bucket: !Ref Bucket 15 | PolicyDocument: 16 | Fn::Sub: 17 | - !ReadFile 'bucketPolicyDoc.json' 18 | - bucket: !Ref Bucket 19 | account: !Ref currentAccount 20 | 21 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-functions-in-cfn/bucketPolicyDoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Action": [ 6 | "s3:GetObject" 7 | ], 8 | "Effect": "Allow", 9 | "Resource": "arn:aws:s3:::${bucket}/*", 10 | "Principal": { 11 | "AWS": "${account}" 12 | } 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-functions-in-cfn/lambda-using-read-file-code.js: -------------------------------------------------------------------------------- 1 | exports.handler = async(event, context) => { 2 | console.log('Event: %s', JSON.stringify(event)); 3 | } 4 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-functions-in-cfn/lambda-using-read-file.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | 4 | Resources: 5 | 6 | LambdaRole: 7 | Type: AWS::IAM::Role 8 | Properties: 9 | RoleName: my-lambda-role 10 | AssumeRolePolicyDocument: 11 | Version: 2012-10-17 12 | Statement: 13 | - Effect: Allow 14 | Principal: 15 | Service: lambda.amazonaws.com 16 | Action: sts:AssumeRole 17 | Path: / 18 | ManagedPolicyArns: 19 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 20 | 21 | LambdaUsingReadFile: 22 | Type: AWS::Lambda::Function 23 | Properties: 24 | FunctionName: my-lambda 25 | Runtime: nodejs18.x 26 | Role: !GetAtt LambdaRole.Arn 27 | Handler: index.handler 28 | Code: 29 | ZipFile: !ReadFile './lambda-using-read-file-code.js' -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-functions-in-cfn/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-global-params/0-include.yml: -------------------------------------------------------------------------------- 1 | Parameters: !Include './global-parameters.yml' 2 | 3 | OrganizationUpdate: 4 | Type: update-organization 5 | Template: ./organization.yml 6 | Skip: true 7 | 8 | includeOther: 9 | DependsOn: UpdateStack 10 | Type: include 11 | Path: ./included.yml 12 | Parameters: 13 | allRegions: !Ref allRegions 14 | primaryRegion: !Ref primaryRegion 15 | resourcePrefix: !Ref resourcePrefix 16 | includeMasterAccount: !Ref includeMasterAccount 17 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-global-params/1-spread-operator.yml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | <<: !Include './global-parameters.yml' 3 | 4 | resourcePrefix: 5 | Type: String 6 | Default: 'yours' 7 | 8 | differentRegion: 9 | Type: String 10 | Default: 'us-east-1' 11 | 12 | OrganizationUpdate: 13 | Type: update-organization 14 | Template: ./organization.yml 15 | Skip: true 16 | 17 | includeOther: 18 | DependsOn: UpdateStack 19 | Type: include 20 | Path: ./included.yml 21 | Parameters: 22 | allRegions: !Ref allRegions 23 | primaryRegion: !Ref differentRegion 24 | resourcePrefix: !Ref resourcePrefix 25 | includeMasterAccount: !Ref includeMasterAccount 26 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-global-params/bucket.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | Bucket: 5 | Type: AWS::S3::Bucket 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-global-params/global-parameters.yml: -------------------------------------------------------------------------------- 1 | allRegions: 2 | Type: List 3 | Default: 4 | - 'eu-central-1' 5 | - 'us-east-1' 6 | 7 | primaryRegion: 8 | Type: String 9 | Default: 'eu-central-1' 10 | 11 | resourcePrefix: 12 | Type: String 13 | Default: 'my' 14 | 15 | includeMasterAccount: 16 | Type: Boolean 17 | Default: true -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-global-params/included.yml: -------------------------------------------------------------------------------- 1 | Parameters: !Include './global-parameters.yml' 2 | 3 | PrimaryRegion: 4 | Type: update-stacks 5 | Template: ./bucket.yml 6 | StackName: !Sub '${resourcePrefix}-stack-name-primary-region' 7 | DefaultOrganizationBindingRegion: !Ref primaryRegion 8 | DefaultOrganizationBinding: 9 | IncludeMasterAccount: !Ref includeMasterAccount 10 | 11 | AllRegions: 12 | Type: update-stacks 13 | Template: ./bucket.yml 14 | StackName: !Sub '${resourcePrefix}-stack-name-all-regions' 15 | DefaultOrganizationBindingRegion: !Ref allRegions 16 | DefaultOrganizationBinding: 17 | IncludeMasterAccount: !Ref includeMasterAccount 18 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-global-params/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-file-twice/0-organization-tasks-1include.yml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | 3 | bucketName: 4 | Type: String 5 | 6 | OrganizationUpdate: 7 | Type: update-organization 8 | Skip: true 9 | Template: ./organization.yml 10 | 11 | Include1: 12 | Type: include 13 | Path: ./included-task-file.yml 14 | Parameters: 15 | resourcePrefix: include1 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-file-twice/0-organization-tasks.yml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | 3 | bucketName: 4 | Type: String 5 | 6 | OrganizationUpdate: 7 | Type: update-organization 8 | Skip: true 9 | Template: ./organization.yml 10 | 11 | Include1: 12 | Type: include 13 | Path: ./included-task-file.yml 14 | Parameters: 15 | resourcePrefix: include1 16 | 17 | Include2: 18 | Type: include 19 | Path: ./included-task-file.yml 20 | Parameters: 21 | resourcePrefix: include2 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-file-twice/1-organization-tasks-missing-param.yml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | 3 | bucketName: 4 | Type: String 5 | 6 | OrganizationUpdate: 7 | Type: update-organization 8 | Skip: true 9 | Template: ./organization.yml 10 | 11 | Include1: 12 | Type: include 13 | Path: ./included-task-file.yml -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-file-twice/included-task-file.yml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | resourcePrefix: 3 | Type: String 4 | Default: my 5 | 6 | bucketName: 7 | Type: String 8 | 9 | Template: 10 | Type: update-stacks 11 | Template: resources/bucket.yml 12 | StackName: !Sub ${resourcePrefix}-my-stack-name 13 | DefaultOrganizationBindingRegion: eu-west-1 14 | DefaultOrganizationBinding: 15 | IncludeMasterAccount: true 16 | 17 | CopyS3File: 18 | Type: copy-to-s3 19 | RemotePath: !Sub s3://${bucketName}/${resourcePrefix}-file.txt 20 | LocalPath: ./resources/file.txt 21 | OrganizationBinding: 22 | IncludeMasterAccount: true 23 | Region: eu-central-1 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-file-twice/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-file-twice/resources/bucket.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | Bucket: 5 | Type: AWS::S3::Bucket 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-file-twice/resources/file.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/test/integration-tests/resources/scenario-include-file-twice/resources/file.txt -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-various/1-deploy.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | TestIncludes: 8 | Type: update-stacks 9 | StackName: test-includes 10 | Template: ./lambda.yml 11 | DefaultOrganizationBindingRegion: eu-west-1 12 | DefaultOrganizationBinding: 13 | IncludeMasterAccount: true -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-various/9-cleanup.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-various/includes/account-a.yml: -------------------------------------------------------------------------------- 1 | AccountA: 2 | Type: OC::ORG::Account 3 | Properties: 4 | RootEmail: account+a@olafconijn.awsapps.com 5 | AccountName: Account A 6 | Tags: 7 | <<: !Include ./tags.yml 8 | tag1: overrwitten-from-within-include 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-various/includes/lambda.js: -------------------------------------------------------------------------------- 1 | exports.handler = function(event, context) { 2 | console.log("REQUEST RECEIVED:\n" + JSON.stringify(event)); 3 | } -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-various/includes/lambda.yml: -------------------------------------------------------------------------------- 1 | Code: 2 | ZipFile: !ReadFile ./includes/lambda.js # !ReadFile gets executed after !Include -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-various/includes/tags.yml: -------------------------------------------------------------------------------- 1 | tag1: defaultValue 2 | tag2: value -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-various/lambda.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Conditions: 4 | ConditionFalse: !Equals [ 'A', 'B' ] 5 | 6 | Resources: 7 | 8 | MyFunction: 9 | Type: AWS::Lambda::Function 10 | Condition: ConditionFalse 11 | Properties: 12 | <<: !Include ./includes/lambda.yml 13 | 14 | Outputs: 15 | AccountATag1: 16 | Value: !GetAtt AccountA.Tags.tag1 17 | Export: 18 | Name: !Sub ${AWS::StackName}-AccountATag1 19 | AccountATag2: 20 | Value: !GetAtt AccountA.Tags.tag2 21 | Export: 22 | Name: !Sub ${AWS::StackName}-AccountATag2 23 | MasterTag1: 24 | Value: !GetAtt MasterAccount.Tags.tag1 25 | Export: 26 | Name: !Sub ${AWS::StackName}-MasterTag1 27 | MasterTag2: 28 | Value: !GetAtt MasterAccount.Tags.tag2 29 | Export: 30 | Name: !Sub ${AWS::StackName}-MasterTag2 31 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-include-various/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | Tags: 11 | <<: !Include ./includes/tags.yml 12 | tag1: overwrittenValue 13 | 14 | 15 | <<: !Include ./includes/account-a.yml 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-included-update-org/buckets.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | Bucket: 5 | Type: AWS::S3::Bucket 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-included-update-org/include-with-tasks.yml: -------------------------------------------------------------------------------- 1 | 2 | Task1: 3 | Type: update-stacks 4 | Template: ./buckets.yml 5 | StackName: slack1 6 | DefaultOrganizationBinding: 7 | Account: "*" 8 | Region: eu-central-1 9 | 10 | Task2: 11 | Type: update-stacks 12 | Template: ./buckets.yml 13 | StackName: slack2 14 | DefaultOrganizationBinding: 15 | Account: !Ref NewAccount 16 | Region: eu-central-1 17 | 18 | Task3: 19 | Type: update-stacks 20 | Template: ./buckets.yml 21 | StackName: slack3 22 | DefaultOrganizationBinding: 23 | Account: 24 | - !Ref NewAccount 25 | - !Ref MasterAccount 26 | Region: eu-central-1 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-included-update-org/include-with-update.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Template: ./organization.yml 5 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-included-update-org/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | 6 | OrganizationRoot: 7 | Type: OC::ORG::OrganizationRoot 8 | Properties: 9 | 10 | MasterAccount: 11 | Type: OC::ORG::MasterAccount 12 | Properties: 13 | AccountName: Organizational Master Account 14 | AccountId: '102625093955' 15 | 16 | NewAccount: 17 | Type: OC::ORG::Account 18 | Properties: 19 | AccountName: Account New 20 | RootEmail: account+new@olafconijn.awsapps.com 21 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-included-update-org/toplevel-tasks.yml: -------------------------------------------------------------------------------- 1 | 2 | Include1: 3 | Type: include 4 | Path: ./include-with-tasks.yml 5 | 6 | Include2: 7 | Type: include 8 | Path: ./include-with-update.yml -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-json-template/1-deploy-json-stack.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | TestJson: 8 | Type: update-stacks 9 | StackName: test-with-json 10 | Template: ./buckets.json 11 | DefaultOrganizationBindingRegion: eu-west-1 12 | DefaultOrganizationBinding: 13 | IncludeMasterAccount: true -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-json-template/9-cleanup-json-stack.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-json-template/buckets.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "OrganizationBinding": { 5 | "Region": "eu-west-1", 6 | "Account": "*", 7 | "IncludeMasterAccount": true 8 | }, 9 | "Type": "AWS::S3::Bucket" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-json-template/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-move-master-acc/1-init-organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-move-master-acc/2-move-to-ou-organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Olaf Conijn 9 | AccountId: '102625093955' 10 | 11 | OU: 12 | Type: OC::ORG::OrganizationalUnit 13 | Properties: 14 | OrganizationalUnitName: ou1 15 | Accounts: !Ref MasterAccount -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-move-master-acc/3-move-to-other-ou-organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Olaf Conijn 9 | AccountId: '102625093955' 10 | 11 | OU: 12 | Type: OC::ORG::OrganizationalUnit 13 | Properties: 14 | OrganizationalUnitName: ou1 15 | 16 | OU2: 17 | Type: OC::ORG::OrganizationalUnit 18 | Properties: 19 | OrganizationalUnitName: ou2 20 | Accounts: !Ref MasterAccount -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-move-master-acc/4-back-to-org-root-organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Olaf Conijn 9 | AccountId: '102625093955' 10 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-move-master-acc/state.json: -------------------------------------------------------------------------------- 1 | { 2 | "masterAccountId": "102625093955", 3 | "bindings": { 4 | "OC::ORG::MasterAccount": { 5 | "MasterAccount": { 6 | "type": "OC::ORG::MasterAccount", 7 | "logicalId": "MasterAccount", 8 | "physicalId": "102625093955", 9 | "lastCommittedHash": "281db6b2c685159c8f11b2c8289abd7b" 10 | } 11 | }, 12 | "OC::ORG::OrganizationRoot": { 13 | "OrganizationRoot": { 14 | "type": "OC::ORG::OrganizationRoot", 15 | "logicalId": "OrganizationRoot", 16 | "physicalId": "r-kvte", 17 | "lastCommittedHash": "6be66ccf6b2a5417439fec93c294f165" 18 | } 19 | }, 20 | "OC::ORG::OrganizationalUnit": {} 21 | }, 22 | "stacks": {}, 23 | "values": { 24 | "organization.template.hash": "1f7c06baf83ee72e843890bce9790d2f" 25 | }, 26 | "previousTemplate": "{\"AWSTemplateFormatVersion\":\"2010-09-09-OC\",\"Description\":\"default template generated for organization with master account 102625093955\",\"Organization\":{\"MasterAccount\":{\"Type\":\"OC::ORG::MasterAccount\",\"Properties\":{\"AccountName\":\"Olaf Conijn\",\"AccountId\":\"102625093955\"}},\"OrganizationRoot\":{\"Type\":\"OC::ORG::OrganizationRoot\",\"Properties\":null}}}" 27 | } -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-nested-ou/0-state.json: -------------------------------------------------------------------------------- 1 | { 2 | "masterAccountId": "102625093955", 3 | "bindings": { 4 | "OC::ORG::MasterAccount": { 5 | "MasterAccount": { 6 | "type": "OC::ORG::MasterAccount", 7 | "logicalId": "MasterAccount", 8 | "physicalId": "102625093955", 9 | "lastCommittedHash": "281db6b2c685159c8f11b2c8289abd7b" 10 | } 11 | }, 12 | "OC::ORG::OrganizationRoot": { 13 | "OrganizationRoot": { 14 | "type": "OC::ORG::OrganizationRoot", 15 | "logicalId": "OrganizationRoot", 16 | "physicalId": "r-kvte", 17 | "lastCommittedHash": "6be66ccf6b2a5417439fec93c294f165" 18 | } 19 | }, 20 | "OC::ORG::OrganizationalUnit": {} 21 | }, 22 | "stacks": {}, 23 | "values": { 24 | "organization.template.hash": "1f7c06baf83ee72e843890bce9790d2f" 25 | }, 26 | "previousTemplate": "{\"AWSTemplateFormatVersion\":\"2010-09-09-OC\",\"Description\":\"default template generated for organization with master account 102625093955\",\"Organization\":{\"MasterAccount\":{\"Type\":\"OC::ORG::MasterAccount\",\"Properties\":{\"AccountName\":\"Olaf Conijn\",\"AccountId\":\"102625093955\"}},\"OrganizationRoot\":{\"Type\":\"OC::ORG::OrganizationRoot\",\"Properties\":null}}}" 27 | } -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-nested-ou/1-init-organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-nested-ou/2-create-parent-child-ou.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | ParentOU: 12 | Type: OC::ORG::OrganizationalUnit 13 | Properties: 14 | OrganizationalUnitName: parent 15 | OrganizationalUnits: !Ref ChildOU 16 | 17 | ChildOU: 18 | Type: OC::ORG::OrganizationalUnit 19 | Properties: 20 | OrganizationalUnitName: child -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-nested-ou/3-swap-child-parent-ou.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | ParentOU: 12 | Type: OC::ORG::OrganizationalUnit 13 | Properties: 14 | OrganizationalUnitName: parent 15 | 16 | ChildOU: 17 | Type: OC::ORG::OrganizationalUnit 18 | Properties: 19 | OrganizationalUnitName: child 20 | OrganizationalUnits: !Ref ParentOU -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-nested-ou/4-delete-parent-keep-child.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | ParentOU: 12 | Type: OC::ORG::OrganizationalUnit 13 | Properties: 14 | OrganizationalUnitName: parent -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-nested-ou/5-three-levels-deep.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | ParentOU: 12 | Type: OC::ORG::OrganizationalUnit 13 | Properties: 14 | OrganizationalUnitName: parent 15 | OrganizationalUnits: !Ref IntermediateOU 16 | 17 | IntermediateOU: 18 | Type: OC::ORG::OrganizationalUnit 19 | Properties: 20 | OrganizationalUnitName: middle 21 | OrganizationalUnits: 22 | - !Ref Child1OU 23 | - !Ref Child2OU 24 | 25 | Child1OU: 26 | Type: OC::ORG::OrganizationalUnit 27 | Properties: 28 | OrganizationalUnitName: child1 29 | 30 | Child2OU: 31 | Type: OC::ORG::OrganizationalUnit 32 | Properties: 33 | OrganizationalUnitName: child2 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-nested-ou/6-duplicate-names.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | ParentOU: 12 | Type: OC::ORG::OrganizationalUnit 13 | Properties: 14 | OrganizationalUnitName: parent 15 | OrganizationalUnits: 16 | - !Ref Child1OU 17 | 18 | IntermediateOU: 19 | Type: OC::ORG::OrganizationalUnit 20 | Properties: 21 | OrganizationalUnitName: middle 22 | OrganizationalUnits: 23 | - !Ref Child2OU 24 | 25 | Child0OU: 26 | Type: OC::ORG::OrganizationalUnit 27 | Properties: 28 | OrganizationalUnitName: child 29 | 30 | Child1OU: 31 | Type: OC::ORG::OrganizationalUnit 32 | Properties: 33 | OrganizationalUnitName: child 34 | 35 | Child2OU: 36 | Type: OC::ORG::OrganizationalUnit 37 | Properties: 38 | OrganizationalUnitName: child 39 | OrganizationalUnits: 40 | - !Ref Child0OU -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-nested-ou/7-cleanup-organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-new-account/buckets.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Organization: !Include ./organization.yml 4 | 5 | Resources: 6 | Bucket: 7 | OrganizationBinding: 8 | Region: eu-west-1 9 | Account: '*' 10 | IncludeMasterAccount: true 11 | Type: AWS::S3::Bucket 12 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-new-account/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | NewAccount: 12 | Type: OC::ORG::Account 13 | Properties: 14 | AccountName: A new account 15 | AccountId: '123456654321' 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-new-account/task.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: false 5 | Template: ./organization.yml 6 | 7 | Task: 8 | Type: update-stacks 9 | StackName: test-with-very-large-stack 10 | Template: ./buckets.yml 11 | DefaultOrganizationBindingRegion: eu-west-1 12 | DefaultOrganizationBinding: 13 | Account: "*" 14 | 15 | CopyToS3WithNewAccount: 16 | Type: copy-to-s3 17 | RemotePath: !Sub 's3://asdasd/${NewAccount}/file2.txt' 18 | LocalPath: ./task.yml 19 | OrganizationBinding: 20 | Account: !Ref AccountA 21 | Region: eu-central-1 22 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-no-bucket/1-deploy-no-bucket.yml: -------------------------------------------------------------------------------- 1 | OrganizationUpdate: 2 | Type: update-organization 3 | Template: ./organization.yml 4 | 5 | MyRoles: 6 | Type: update-stacks 7 | StackName: integration-test-my-role 8 | DefaultOrganizationBindingRegion: us-east-1 9 | DefaultOrganizationBinding: { Account: '*' } 10 | Template: ./my-role.yml 11 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-no-bucket/my-role.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | 5 | MyRole: 6 | Type: AWS::IAM::Role 7 | Properties: 8 | RoleName: MyRole 9 | AssumeRolePolicyDocument: 10 | Version: 2012-10-17 11 | Statement: 12 | - Effect: Allow 13 | Action: sts:AssumeRole 14 | Principal: 15 | AWS: !Ref MasterAccount -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-no-bucket/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-non-local-templates/0-tasks.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | CopyToS3: 8 | Type: copy-to-s3 9 | RemotePath: s3://scenario-non-local-templates/xyz/buckets.yml 10 | LocalPath: ./buckets.yml 11 | OrganizationBinding: 12 | IncludeMasterAccount: true 13 | Region: eu-west-1 14 | 15 | BucketsFromS3: 16 | DependsOn: CopyToS3 17 | Type: update-stacks 18 | StackName: buckets-from-remote-s3-template 19 | Template: s3://scenario-non-local-templates/xyz/buckets.yml #todo: support !Sub 20 | OrganizationBinding: 21 | IncludeMasterAccount: true 22 | Region: eu-west-1 23 | 24 | BucketsFromHTTP: 25 | DependsOn: CopyToS3 26 | Type: update-stacks 27 | StackName: buckets-from-remote-https-template 28 | Template: https://raw.githubusercontent.com/org-formation/org-formation-cli/master/test/integration-tests/resources/scenario-very-large-stack/buckets.yml 29 | OrganizationBinding: 30 | IncludeMasterAccount: true 31 | Region: eu-west-1 32 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-non-local-templates/9-cleanup-tasks.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-non-local-templates/buckets.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | Bucket: 5 | OrganizationBinding: 6 | Region: eu-west-1 7 | Account: '*' 8 | IncludeMasterAccount: true 9 | Type: AWS::S3::Bucket 10 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-non-local-templates/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-organization-file-s3/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-organization-file-s3/task.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: false 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-perform-tasks/0-tasks.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Template: ./organization.yml 5 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-perform-tasks/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | 6 | OrganizationRoot: 7 | Type: OC::ORG::OrganizationRoot 8 | Properties: 9 | 10 | MasterAccount: 11 | Type: OC::ORG::MasterAccount 12 | Properties: 13 | AccountName: Organizational Master Account 14 | AccountId: '102625093955' 15 | 16 | OrganizationBuildAccount: 17 | Type: OC::ORG::Account 18 | Properties: 19 | AccountName: Account A 20 | AccountId: '340381375986' 21 | RootEmail: account+a@olafconijn.awsapps.com 22 | 23 | AccountB: 24 | Type: OC::ORG::Account 25 | Properties: 26 | AccountName: Account B 27 | AccountId: '362239514602' 28 | RootEmail: account+b@olafconijn.awsapps.com 29 | OrganizationAccessRoleName: CustomCrossAccountRole 30 | 31 | AccountC: 32 | Type: OC::ORG::Account 33 | Properties: 34 | AccountName: Account C 35 | AccountId: '673026687213' 36 | RootEmail: account+c@olafconijn.awsapps.com 37 | OrganizationAccessRoleName: AnotherCustomRole 38 | 39 | AnotherAccount: 40 | Type: OC::ORG::Account 41 | Properties: 42 | AccountName: Users Account 43 | AccountId: '549476213961' 44 | RootEmail: account+users@olafconijn.awsapps.com 45 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-register-type/1-register-type.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | RegisterType: 8 | Type: register-type 9 | SchemaHandlerPackage: s3://community-resource-provider-catalog/community-servicequotas-s3-0.1.0.zip 10 | ResourceType: 'Community::ServiceQuotas::S3' 11 | MaxConcurrentTasks: 5 12 | FailedTaskTolerance: 5 13 | OrganizationBinding: 14 | IncludeMasterAccount: true 15 | Account: '*' 16 | Region: eu-west-1 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-register-type/2-register-type-changed-org.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization-2.yml 6 | 7 | RegisterType: 8 | Type: register-type 9 | SchemaHandlerPackage: s3://community-resource-provider-catalog/community-servicequotas-s3-0.1.0.zip 10 | ResourceType: 'Community::ServiceQuotas::S3' 11 | MaxConcurrentTasks: 5 12 | FailedTaskTolerance: 5 13 | OrganizationBinding: 14 | IncludeMasterAccount: true 15 | Account: '*' 16 | Region: eu-west-1 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-register-type/3-register-type-added-account.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization-3.yml 6 | 7 | RegisterType: 8 | Type: register-type 9 | SchemaHandlerPackage: s3://community-resource-provider-catalog/community-servicequotas-s3-0.1.0.zip 10 | ResourceType: 'Community::ServiceQuotas::S3' 11 | MaxConcurrentTasks: 5 12 | FailedTaskTolerance: 5 13 | OrganizationBinding: 14 | IncludeMasterAccount: true 15 | Account: '*' 16 | Region: eu-west-1 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-register-type/4-move-register-type-to-include.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization-3.yml 6 | 7 | RegisterType: 8 | Type: register-type 9 | SchemaHandlerPackage: s3://community-resource-provider-catalog/community-servicequotas-s3-0.1.0.zip 10 | ResourceType: 'Community::ServiceQuotas::S3' 11 | MaxConcurrentTasks: 5 12 | FailedTaskTolerance: 5 13 | OrganizationBinding: 14 | IncludeMasterAccount: true 15 | Account: '*' 16 | Region: eu-west-1 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-register-type/9-cleanup.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-register-type/include-with-type.yml: -------------------------------------------------------------------------------- 1 | 2 | RegisterType: 3 | Type: register-type 4 | SchemaHandlerPackage: s3://community-resource-provider-catalog/community-servicequotas-s3-0.1.0.zip 5 | ResourceType: 'Community::ServiceQuotas::S3' 6 | MaxConcurrentTasks: 5 7 | FailedTaskTolerance: 5 8 | OrganizationBinding: 9 | IncludeMasterAccount: true 10 | Account: '*' 11 | Region: eu-west-1 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-register-type/organization-2.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: XXXX 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | 17 | 18 | # this is here to have the comparison with other org file to -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-register-type/organization-3.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: XXXX 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | 17 | UsersAccount: 18 | Type: OC::ORG::Account 19 | Properties: 20 | RootEmail: account+users@olafconijn.awsapps.com 21 | AccountName: Users Account 22 | 23 | # this is here to have the comparison with other org file to -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-register-type/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-serverless-com-task/1-deploy-serverless-workload-2targets.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | ServerlessWorkload: 8 | Type: update-serverless.com # type 9 | Config: serverless.yml # serverless file, optional 10 | Path: ./workload/ # used to package / calculate hash 11 | RunNpmInstall: true 12 | OrganizationBinding: 13 | IncludeMasterAccount: true 14 | Account: !Ref AccountA 15 | Region: eu-central-1 16 | MaxConcurrentTasks: 1 17 | FailedTaskTolerance: 0 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-serverless-com-task/2-update-serverless-workload-with-parameters.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | ServerlessWorkload: 8 | Type: update-serverless.com # type 9 | Config: serverless.yml # serverless file, optional 10 | Path: ./workload/ # used to package / calculate hash 11 | RunNpmInstall: true 12 | OrganizationBinding: 13 | IncludeMasterAccount: true 14 | Account: !Ref AccountA 15 | Region: eu-central-1 16 | Parameters: 17 | param1: !Sub 'sub expression ${AWS::AccountId}' 18 | param2: !GetAtt AccountA.AccountName 19 | MaxConcurrentTasks: 1 20 | FailedTaskTolerance: 0 21 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-serverless-com-task/3-deploy-serverless-workload-1target.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | ServerlessWorkload: 8 | Type: update-serverless.com # type 9 | Config: serverless.yml # serverless file, optional 10 | Path: ./workload/ # used to package / calculate hash 11 | RunNpmInstall: true 12 | OrganizationBinding: 13 | Account: !Ref AccountA 14 | Region: eu-central-1 15 | Parameters: 16 | param1: !Sub 'sub expression ${AWS::AccountId}' 17 | param2: !GetAtt AccountA.AccountName 18 | MaxConcurrentTasks: 1 19 | FailedTaskTolerance: 0 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-serverless-com-task/4-remove-serverless-workload-task.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-serverless-com-task/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-serverless-com-task/workload/.gitignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-serverless-com-task/workload/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports.hello = async event => { 4 | return { 5 | statusCode: 200, 6 | body: JSON.stringify( 7 | { 8 | message: 'Go Serverless v1.0! Your function executed successfully!', 9 | input: event, 10 | }, 11 | null, 12 | 2 13 | ), 14 | }; 15 | 16 | // Use this code if you don't use the http event with the LAMBDA-PROXY integration 17 | // return { message: 'Go Serverless v1.0! Your function executed successfully!', event }; 18 | }; 19 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-serverless-com-task/workload/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workload", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1 5 | } 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-serverless-com-task/workload/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workload", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "handler.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": {} 12 | } 13 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-skip-tasks/included.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/test/integration-tests/resources/scenario-skip-tasks/included.yml -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-skip-tasks/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-task-file-parameters/bucket.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | Bucket: 5 | Type: AWS::S3::Bucket 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-task-file-parameters/included-task-file-with-pseudo-param.yml: -------------------------------------------------------------------------------- 1 | 2 | Parameters: 3 | 4 | stackPrefix: 5 | Description: 6 | Type: String 7 | 8 | includeMasterAccount: 9 | Description: 10 | Type: Boolean 11 | Default: true 12 | 13 | Mappings: 14 | Partition: 15 | BindingRegions: 16 | aws: eu-west-1 17 | aws-us-gov: us-gov-west-1 18 | 19 | BucketTemplate: 20 | Type: update-stacks 21 | Template: ./bucket.yml 22 | StackName: !Sub ${stackPrefix}-scenario-stack-parameters 23 | DefaultOrganizationBindingRegion: !FindInMap [ Partition, BindingRegions, !Ref AWS::Partition ] 24 | DefaultOrganizationBinding: 25 | IncludeMasterAccount: !Ref includeMasterAccount -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-task-file-parameters/included-task-file.yml: -------------------------------------------------------------------------------- 1 | 2 | Parameters: 3 | 4 | partition: 5 | Type: String 6 | 7 | stackPrefix: 8 | Description: 9 | Type: String 10 | 11 | includeMasterAccount: 12 | Description: 13 | Type: Boolean 14 | Default: true 15 | 16 | Mappings: 17 | Partition: 18 | BindingRegions: 19 | aws: eu-west-1 20 | aws-us-gov: us-gov-west-1 21 | 22 | BucketTemplate: 23 | Type: update-stacks 24 | Template: ./bucket.yml 25 | StackName: !Sub ${stackPrefix}-scenario-stack-parameters 26 | DefaultOrganizationBindingRegion: !FindInMap [ Partition, BindingRegions, !Ref partition ] 27 | DefaultOrganizationBinding: 28 | IncludeMasterAccount: !Ref includeMasterAccount -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-task-file-parameters/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-task-that-fails/invalid-template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Parameters: 4 | ThisWillNotBePassed: 5 | Type: String 6 | 7 | 8 | Organization: !Include ./organization.yml 9 | 10 | Resources: 11 | InvalidType: 12 | Type: XX::S3::Bucket 13 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-task-that-fails/organization-tasks.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Template: ./organization.yml 5 | 6 | CfnTemplate: 7 | Type: update-stacks 8 | Template: ./invalid-template.yml 9 | StackName: invalid-template 10 | DefaultOrganizationBindingRegion: eu-west-1 11 | DefaultOrganizationBinding: 12 | Account: '*' 13 | IncludeMasterAccount: true 14 | MaxConcurrentStacks: 2 15 | FailedStackTolerance: 0 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-task-that-fails/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-template-all/1-deploy-text-templated-things.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Template: ./organization.njk 5 | Skip: true 6 | TemplatingContext: !Include ./templating-context.json 7 | 8 | Include: 9 | Type: include 10 | Path: ./included-task.njk 11 | TemplatingContext: !Include ./templating-context.json -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-template-all/9-cleanup-text-templated-things.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.njk 6 | TemplatingContext: !Include ./templating-context.json -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-template-all/buckets.yml: -------------------------------------------------------------------------------- 1 | 2 | Resources: 3 | Bucket: 4 | OrganizationBinding: 5 | Region: eu-west-1 6 | Account: '*' 7 | IncludeMasterAccount: true 8 | Type: AWS::S3::Bucket 9 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-template-all/included-task.njk: -------------------------------------------------------------------------------- 1 | 2 | {% for team in teams %} 3 | buckets{{ team.name | capitalize }}: 4 | Type: update-stacks 5 | StackName: buckets-{{ team.name }} 6 | Template: ./buckets.yml 7 | DefaultOrganizationBindingRegion: eu-west-1 8 | MaxConcurrentStacks: 10 9 | DefaultOrganizationBinding: 10 | IncludeMasterAccount: true 11 | {% endfor %} 12 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-template-all/organization.njk: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | {% for team in teams %} 12 | # Account{{ team.name | capitalize }}: 13 | # Type: OC::ORG::Account 14 | # Properties: 15 | # RootEmail: {{ team.email }} 16 | # AccountName: Account {{ team.name | capitalize }} 17 | {% endfor %} -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-template-all/templating-context.json: -------------------------------------------------------------------------------- 1 | { 2 | "teams": [ 3 | { "name": "a", "email": "account+a@olafconijn.awsapps.com" }, 4 | { "name": "b", "email": "account+b@olafconijn.awsapps.com" }, 5 | { "name": "c", "email": "account+c@olafconijn.awsapps.com" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-template-mixed/1-deploy.yml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | switch: 3 | Type: Boolean 4 | Default: false 5 | 6 | OrganizationBindings: 7 | MasterAccount: 8 | IncludeMasterAccount: true 9 | Region: eu-west-1 10 | 11 | OrganizationUpdate: 12 | Type: update-organization 13 | Template: ./organization.yml 14 | Skip: true 15 | 16 | Include: 17 | Type: include 18 | Path: ./included-task.njk 19 | TemplatingContext: 20 | Teams: !Include ./teams.json 21 | Parameters: 22 | Switch: !Ref switch 23 | Partition: !Ref AWS::Partition 24 | Substitute: !Sub 'Current Account: ${CurrentAccount}' 25 | Accounts: Fn::EnumTargetAccounts MasterAccount 26 | Regions: Fn::EnumTargetRegions MasterAccount 27 | 28 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-template-mixed/9-cleanup.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-template-mixed/buckets.yml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Switch: 3 | Type: String 4 | Partition: 5 | Type: String 6 | Substitute: 7 | Type: String 8 | 9 | Resources: 10 | Bucket: 11 | Type: AWS::S3::Bucket 12 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-template-mixed/included-task.njk: -------------------------------------------------------------------------------- 1 | 2 | {% for team in Teams %} 3 | buckets{{ team.name | capitalize }}: 4 | Type: update-stacks 5 | StackName: mixed-buckets-{{ team.name }} 6 | Template: ./buckets.yml 7 | MaxConcurrentStacks: 10 8 | Parameters: 9 | Switch: {{ Parameters.Switch }} 10 | Partition: {{ Parameters.Partition | object }} 11 | Substitute: {{ Parameters.Substitute | object }} 12 | OrganizationBinding: 13 | Region: 14 | {% for region in Regions %} 15 | - {{region}} 16 | {% endfor %} 17 | Account: 18 | {% for acc in Accounts %} 19 | - !Ref {{acc.LogicalId}} 20 | {% endfor %} 21 | {% endfor %} 22 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-template-mixed/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-template-mixed/teams.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "name": "a", "email": "account+a@olafconijn.awsapps.com" }, 3 | { "name": "b", "email": "account+b@olafconijn.awsapps.com" }, 4 | { "name": "c", "email": "account+c@olafconijn.awsapps.com" } 5 | ] 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-templating/nunjucks-template-included.njk: -------------------------------------------------------------------------------- 1 | 2 | Version: 2012-10-17 3 | Statement: 4 | - Sid: AssumeRole1 5 | Effect: Allow 6 | Principal: 7 | Service: cloudtrail.amazonaws.com 8 | Action: sts:AssumeRole 9 | 10 | {% for role in roleNames %} 11 | # comment: {{ role }} 12 | {% endfor %} -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-templating/nunjucks-template-with-include.njk: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | 3 | Parameters: 4 | 5 | resourcePrefix: 6 | Type: String 7 | 8 | Resources: 9 | 10 | {% for role in roleNames %} 11 | Role{{ role }}: 12 | Type: "AWS::IAM::Role" 13 | Properties: 14 | RoleName: !Sub '${resourcePrefix}-{{ role }}' 15 | AssumeRolePolicyDocument: !Include './nunjucks-template-included.njk' 16 | {% endfor %} 17 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-templating/nunjucks-template.njk: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | 3 | Parameters: 4 | 5 | resourcePrefix: 6 | Type: String 7 | 8 | Resources: 9 | 10 | {% for role in roleNames %} 11 | Role{{ role }}: 12 | Type: "AWS::IAM::Role" 13 | Properties: 14 | RoleName: !Sub '${resourcePrefix}-{{ role }}' 15 | AssumeRolePolicyDocument: 16 | Version: 2012-10-17 17 | Statement: 18 | - Sid: AssumeRole1 19 | Effect: Allow 20 | Principal: 21 | Service: cloudtrail.amazonaws.com 22 | Action: sts:AssumeRole 23 | {% endfor %} 24 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-templating/organization-tasks.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | NjkTemplate: 8 | Type: update-stacks 9 | Template: ./nunjucks-template.njk 10 | StackName: nunjucks-template 11 | DefaultOrganizationBindingRegion: eu-west-1 12 | DefaultOrganizationBinding: 13 | Account: '*' 14 | IncludeMasterAccount: true 15 | TemplatingContext: 16 | roleNames: 17 | - "Role1" 18 | - "Role2" 19 | Parameters: 20 | resourcePrefix: "my" 21 | MaxConcurrentStacks: 2 22 | FailedStackTolerance: 0 23 | 24 | NjkTemplateWithInclude: 25 | Type: update-stacks 26 | Template: ./nunjucks-template-with-include.njk 27 | StackName: nunjucks-template2 28 | DefaultOrganizationBindingRegion: eu-west-1 29 | DefaultOrganizationBinding: 30 | Account: '*' 31 | IncludeMasterAccount: true 32 | TemplatingContext: 33 | roleNames: 34 | - "Role1" 35 | - "Role2" 36 | Parameters: 37 | resourcePrefix: "my2" 38 | MaxConcurrentStacks: 2 39 | FailedStackTolerance: 0 -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-text-templating/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-tf-task/1-deploy-tf-workload.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | TfWorkfload: 8 | Type: apply-tf 9 | Path: ./folder-with-terraform 10 | OrganizationBinding: 11 | IncludeMasterAccount: false 12 | Region: "eu-central-1" 13 | Account: !Ref AccountA 14 | BackendConfig: 15 | bucket: "my-s3-state-bucket" 16 | region: "us-east-1" 17 | key: !Sub ${CurrentAccount}.tfstate 18 | Parameters: 19 | tfvarforbucketname: !Sub ${CurrentAccount}-bucket -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-tf-task/2-remove-tf-workload.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-tf-task/folder-with-terraform/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | backend "s3" { 3 | } 4 | } 5 | 6 | provider "aws" {} 7 | 8 | variable "tfvarforbucketname" {} 9 | 10 | resource "aws_s3_bucket" "b" { 11 | bucket = var.tfvarforbucketname 12 | 13 | tags = { 14 | ManagedBy = "Terraform" 15 | DeployedWith = "org-formation" 16 | } 17 | } -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-tf-task/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | Tags: 11 | Tag: TagValue1 12 | 13 | AccountA: 14 | Type: OC::ORG::Account 15 | Properties: 16 | RootEmail: account+a@olafconijn.awsapps.com 17 | AccountName: Account A 18 | Tags: 19 | Tag: TagValue2 20 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-custom-role/1-deploy-stacks-custom-roles.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | MyRoles: 8 | Type: update-stacks 9 | StackName: integration-test-my-roles 10 | Template: ./my-roles.yml 11 | 12 | TestCustomRole: 13 | DependsOn: MyRoles 14 | Type: update-stacks 15 | StackName: integration-test-custom-role 16 | Template: ./buckets.yml 17 | CloudFormationRoleName: MyCloudFormationRole 18 | TaskRoleName: MyTaskRole -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-custom-role/2-cleanup-stacks-custom-roles.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | MyRoles: 8 | Type: update-stacks 9 | StackName: integration-test-my-roles 10 | Template: ./my-roles.yml -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-custom-role/buckets.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | Bucket: 5 | OrganizationBinding: 6 | Region: eu-west-1 7 | Account: !Ref AccountA 8 | Type: AWS::S3::Bucket 9 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-custom-role/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-stack-policy/1-deploy-stacks-with-stack-policy.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | TestCustomRole: 8 | DependsOn: MyRoles 9 | Type: update-stacks 10 | StackName: test-with-stack-policy 11 | Template: ./buckets.yml 12 | StackPolicy: 13 | Statement: 14 | - Effect: Deny 15 | Action: 'Update:*' 16 | Principal: '*' 17 | Resource: '*' 18 | DefaultOrganizationBindingRegion: eu-west-1 19 | DefaultOrganizationBinding: 20 | IncludeMasterAccount: true -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-stack-policy/2-update-stacks-with-stack-policy.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | TestCustomRole: 8 | DependsOn: MyRoles 9 | Type: update-stacks 10 | StackName: test-with-stack-policy 11 | Template: ./buckets-update.yml 12 | StackPolicy: 13 | Statement: 14 | - Effect: Deny 15 | Action: 'Update:*' 16 | Principal: '*' 17 | Resource: '*' 18 | DefaultOrganizationBindingRegion: eu-west-1 19 | DefaultOrganizationBinding: 20 | IncludeMasterAccount: true -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-stack-policy/3-update-stack-policy.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | TestCustomRole: 8 | DependsOn: MyRoles 9 | Type: update-stacks 10 | StackName: test-with-stack-policy 11 | Template: ./buckets.yml 12 | StackPolicy: 13 | Statement: 14 | - Effect: Allow 15 | Action: 'Update:*' 16 | Principal: '*' 17 | Resource: '*' 18 | DefaultOrganizationBindingRegion: eu-west-1 19 | DefaultOrganizationBinding: 20 | IncludeMasterAccount: true -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-stack-policy/4-update-stack-policy-using-flag.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | TestCustomRole: 8 | DependsOn: MyRoles 9 | Type: update-stacks 10 | StackName: test-with-stack-policy 11 | Template: ./buckets.yml 12 | UpdateProtection: true 13 | DefaultOrganizationBindingRegion: eu-west-1 14 | DefaultOrganizationBinding: 15 | IncludeMasterAccount: true -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-stack-policy/5-update-stack-policy-using-flag-false.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | TestCustomRole: 8 | DependsOn: MyRoles 9 | Type: update-stacks 10 | StackName: test-with-stack-policy 11 | Template: ./buckets.yml 12 | UpdateProtection: false 13 | DefaultOrganizationBindingRegion: eu-west-1 14 | DefaultOrganizationBinding: 15 | IncludeMasterAccount: true -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-stack-policy/6-update-stack-policy-clearing-policy.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | TestCustomRole: 8 | DependsOn: MyRoles 9 | Type: update-stacks 10 | StackName: test-with-stack-policy 11 | Template: ./buckets.yml 12 | DefaultOrganizationBindingRegion: eu-west-1 13 | DefaultOrganizationBinding: 14 | IncludeMasterAccount: true -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-stack-policy/9-cleanup-stacks-with-stack-policy.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-stack-policy/buckets-update.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | BucketX: 5 | Type: AWS::S3::Bucket 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-stack-policy/buckets.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | Bucket: 5 | Type: AWS::S3::Bucket 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-stack-policy/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-tags/1-deploy-stacks-with-tags.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | TestUpdateTags: 8 | Type: update-stacks 9 | StackName: test-with-stack-tags 10 | Template: ./buckets.yml 11 | Tags: 12 | Tag: tag-val1 13 | AnotherTag: tag-val2 14 | DefaultOrganizationBindingRegion: eu-west-1 15 | DefaultOrganizationBinding: 16 | IncludeMasterAccount: true -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-tags/2-deploy-stacks-without-tags.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | TestUpdateTags: 8 | Type: update-stacks 9 | StackName: test-with-stack-tags 10 | Template: ./buckets.yml 11 | DefaultOrganizationBindingRegion: eu-west-1 12 | DefaultOrganizationBinding: 13 | IncludeMasterAccount: true -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-tags/9-cleanup-stacks-with-tags.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-tags/buckets.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Resources: 4 | Bucket: 5 | Type: AWS::S3::Bucket 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-update-stacks-tags/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-very-large-stack/1-deploy-very-large-stack.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | 7 | TestVeryLargeStack: 8 | Type: update-stacks 9 | StackName: test-with-very-large-stack 10 | Template: ./buckets.yml 11 | DefaultOrganizationBindingRegion: eu-west-1 12 | DefaultOrganizationBinding: 13 | IncludeMasterAccount: true -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-very-large-stack/9-cleanup-very-large-stack.yml: -------------------------------------------------------------------------------- 1 | 2 | OrganizationUpdate: 3 | Type: update-organization 4 | Skip: true 5 | Template: ./organization.yml 6 | -------------------------------------------------------------------------------- /test/integration-tests/resources/scenario-very-large-stack/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 102625093955 3 | 4 | Organization: 5 | MasterAccount: 6 | Type: OC::ORG::MasterAccount 7 | Properties: 8 | AccountName: Organizational Master Account 9 | AccountId: '102625093955' 10 | 11 | AccountA: 12 | Type: OC::ORG::Account 13 | Properties: 14 | RootEmail: account+a@olafconijn.awsapps.com 15 | AccountName: Account A 16 | -------------------------------------------------------------------------------- /test/integration-tests/scenario-new-account.test.ts: -------------------------------------------------------------------------------- 1 | import { ValidateTasksCommand } from '~commands/index'; 2 | import { PrintTasksCommand } from '~commands/print-tasks'; 3 | import { IIntegrationTestContext, baseBeforeAll, baseAfterAll } from './base-integration-test'; 4 | 5 | const basePathForScenario = './test/integration-tests/resources/scenario-new-account/'; 6 | 7 | describe('when adding new account', () => { 8 | let context: IIntegrationTestContext; 9 | 10 | beforeAll(async () => { 11 | context = await baseBeforeAll(); 12 | await context.prepareStateBucket(basePathForScenario + '../state.json'); 13 | 14 | }); 15 | test('validate doesnt throw', async () => { 16 | 17 | const { command } = context; 18 | await ValidateTasksCommand.Perform({ ...command, tasksFile: basePathForScenario + 'task.yml' }); 19 | }); 20 | 21 | test('print doesnt throw', async () => { 22 | const { command } = context; 23 | 24 | await PrintTasksCommand.Perform({ ...command, tasksFile: basePathForScenario + 'task.yml' }); 25 | }); 26 | 27 | afterAll(async () => { 28 | await baseAfterAll(context); 29 | }); 30 | }); -------------------------------------------------------------------------------- /test/integration-tests/temp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/test/integration-tests/temp/.keep -------------------------------------------------------------------------------- /test/resources/budget-alarms/budget-alarms.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: default template generated for organization with master account 507468909204 3 | 4 | Organization: !Include ./organization.yml 5 | 6 | Resources: 7 | 8 | Budget: 9 | OrganizationBinding: 10 | Region: eu-central-1 11 | AccountsWithTag: budget-alarm-threshold 12 | Type: AWS::Budgets::Budget 13 | Properties: 14 | Budget: 15 | BudgetLimit: 16 | Amount: !GetAtt AWSAccount.Tags.budget-alarm-threshold 17 | Unit: USD 18 | TimeUnit: MONTHLY 19 | BudgetType: COST 20 | NotificationsWithSubscribers: 21 | - Notification: 22 | NotificationType: FORECASTED 23 | ComparisonOperator: GREATER_THAN 24 | Threshold: 100 25 | Subscribers: 26 | - SubscriptionType: EMAIL 27 | Address: !GetAtt AWSAccount.RootEmail 28 | 29 | -------------------------------------------------------------------------------- /test/resources/budget-alarms/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Organization: 4 | MasterAccount: 5 | Type: OC::ORG::MasterAccount 6 | Properties: 7 | RootEmail: 'master@org.com' 8 | AccountId: '000000000000' 9 | AccountName: oc test account 2 10 | Tags: 11 | budget-alarm-threshold: '500' 12 | 13 | SharedUsersAccount: 14 | Type: OC::ORG::Account 15 | Properties: 16 | AccountName: Shared Users Account 17 | RootEmail: 'users@org.com' 18 | 19 | SharedServicesAccount: 20 | Type: OC::ORG::Account 21 | Properties: 22 | AccountName: Shared Services Account 23 | RootEmail: 'services@org.com' 24 | 25 | SharedComplianceAccount: 26 | Type: OC::ORG::Account 27 | Properties: 28 | AccountName: Shared Compliance Account 29 | RootEmail: 'compliance@org.com' 30 | Tags: 31 | budget-alarm-threshold: '100' -------------------------------------------------------------------------------- /test/resources/cloudformation-template-params.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | 3 | Parameters: 4 | resourcePrefix: 5 | Type: string 6 | 7 | Resources: 8 | MyDeploymentBucket: 9 | Type: AWS::S3::Bucket 10 | Properties: 11 | BucketName: !Sub '${resourcePrefix}-deployment-deployments-${AWS::AccountId}' 12 | 13 | Outputs: 14 | SlsDeploymentBucketExport: 15 | Value: !Ref MyDeploymentBucket 16 | Export: 17 | Name: my-deployment-bucket 18 | -------------------------------------------------------------------------------- /test/resources/cloudformation-template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | 3 | Resources: 4 | MyDeploymentBucket: 5 | Type: AWS::S3::Bucket 6 | Properties: 7 | BucketName: !Sub 'my-deployment-deployments-${AWS::AccountId}' 8 | 9 | Outputs: 10 | SlsDeploymentBucketExport: 11 | Value: !Ref MyDeploymentBucket 12 | Export: 13 | Name: my-deployment-bucket 14 | -------------------------------------------------------------------------------- /test/resources/cloudtrail/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Organization: 4 | MasterAccount: 5 | Type: OC::ORG::MasterAccount 6 | Properties: 7 | AccountId: '000000000000' 8 | AccountName: oc test account 2 9 | 10 | SharedUsersAccount: 11 | Type: OC::ORG::Account 12 | Properties: 13 | AccountName: Shared Users Account 14 | RootEmail: users@my.org 15 | 16 | SharedServicesAccount: 17 | Type: OC::ORG::Account 18 | Properties: 19 | AccountName: Shared Services Account 20 | RootEmail: services@my.org 21 | 22 | SharedComplianceAccount: 23 | Type: OC::ORG::Account 24 | Properties: 25 | AccountName: Shared Compliance Account 26 | RootEmail: compliance@my.org -------------------------------------------------------------------------------- /test/resources/conditionals/conditionals.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Organization: !Include ./organization.yml 4 | 5 | DefaultOrganizationBindingRegion: eu-central-1 6 | 7 | OrganizationBindings: 8 | 9 | BucketAccountBinding: 10 | Account: !Ref Account1 11 | 12 | DependeeAccount: 13 | Account: !Ref Account2 14 | 15 | Parameters: 16 | 17 | parameter: 18 | Type: String 19 | AllowedValues: [ true, false ] 20 | 21 | Conditions: 22 | 23 | condition: !Equals [ !Ref parameter, true ] 24 | 25 | Resources: 26 | 27 | BucketWithCondition: 28 | Condition: condition 29 | OrganizationBinding: !Ref BucketAccountBinding 30 | DeletionPolicy: Retain 31 | Type: AWS::S3::Bucket 32 | Properties: 33 | BucketName: 'bucket with condition' 34 | 35 | SomethingDependent: 36 | Condition: condition 37 | OrganizationBinding: !Ref DependeeAccount 38 | Type: AWS::Any::thing 39 | Properties: 40 | BucketName: !Sub 'depdendency-${BucketWithCondition}' 41 | 42 | Outputs: 43 | Bucket: 44 | Condition: condition 45 | Value: !Ref BucketWithCondition 46 | Export: 47 | Name: my-bucket-name 48 | -------------------------------------------------------------------------------- /test/resources/custom-parameter-binding/custom-parameter-binding-non-existant.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Organization: !Include ./organization.yml 4 | 5 | OrganizationBinding: 6 | Region: eu-west-1 7 | Account: !Ref Account1 8 | 9 | Parameters: 10 | Param: 11 | Type: String 12 | ExportName: export-name 13 | ExportAccountId: !Ref UnkownAccount 14 | ExportRegion: eu-central-1 15 | 16 | 17 | Resources: 18 | Topic: 19 | Type: AWS::SNS::Topic 20 | Properties: 21 | DisplayName: Topic in Account 1 -------------------------------------------------------------------------------- /test/resources/custom-parameter-binding/custom-parameter-binding.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Organization: !Include ./organization.yml 4 | 5 | OrganizationBinding: 6 | Region: eu-west-1 7 | Account: !Ref Account1 8 | 9 | Parameters: 10 | Param: 11 | Type: String 12 | ExportName: export-name 13 | ExportAccountId: !Ref Account4 14 | ExportRegion: eu-central-1 15 | 16 | 17 | Resources: 18 | Topic: 19 | Type: AWS::SNS::Topic 20 | Properties: 21 | DisplayName: Topic in Account 1 -------------------------------------------------------------------------------- /test/resources/defaults/default-binding.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: 3 | 4 | Organization: !Include ./organization.yml 5 | 6 | DefaultOrganizationBinding: 7 | Region: eu-west-1 8 | Account: !Ref Account1 9 | 10 | Resources: 11 | 12 | Topic: 13 | Type: AWS::SNS::Topic 14 | Properties: 15 | DisplayName: Topic in Account 1 16 | 17 | S3Bucket: 18 | Type: AWS::S3::Bucket 19 | OrganizationBinding: 20 | Region: eu-central-1 21 | Account: !Ref Account2 22 | Properties: 23 | BucketName: Bucket in Account 2 24 | -------------------------------------------------------------------------------- /test/resources/defaults/default-organization-bindings.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: 3 | 4 | Organization: !Include ./organization.yml 5 | 6 | 7 | DefaultOrganizationBinding: 8 | Region: eu-central-1 9 | Account: 10 | - !Ref Account1 11 | - !Ref Account2 12 | 13 | Resources: 14 | Topic1: 15 | Type: AWS::SNS::Topic 16 | Properties: 17 | DisplayName: abc 18 | 19 | S3Bucket1: 20 | Type: AWS::S3::Bucket 21 | Properties: 22 | BucketName: def 23 | 24 | S3Bucket2: 25 | Type: AWS::S3::Bucket 26 | OrganizationBinding: 27 | Region: eu-central-1 28 | Account: 29 | - !Ref Account2 30 | - !Ref Account3 31 | Properties: 32 | BucketName: xyz 33 | 34 | -------------------------------------------------------------------------------- /test/resources/defaults/default-regions.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: 3 | 4 | Organization: !Include ./organization.yml 5 | 6 | DefaultOrganizationBindingRegion: 7 | - eu-west-1 8 | - eu-central-1 9 | 10 | Resources: 11 | 12 | Topic: 13 | Type: AWS::SNS::Topic 14 | OrganizationBinding: 15 | Account: !Ref Account1 16 | Properties: 17 | DisplayName: Topic in eu-west-1 and eu-central-1 18 | 19 | S3Bucket: 20 | Type: AWS::S3::Bucket 21 | OrganizationBinding: 22 | Account: !Ref Account1 23 | Region: us-east-1 24 | Properties: 25 | BucketName: Bucket in us-east-1 26 | -------------------------------------------------------------------------------- /test/resources/depends-on-account/depends-on-account-multiple.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: 3 | 4 | Organization: !Include ./organization.yml 5 | DefaultOrganizationBindingRegion: 'eu-west-1' 6 | 7 | Resources: 8 | 9 | Topic: 10 | Type: AWS::SNS::Topic 11 | DependsOnAccount: 12 | - !Ref Account2 13 | - !Ref Account2 14 | - !Ref Account2 15 | DependsOnRegion: 16 | - us-east-1 17 | - us-east-1 18 | - us-east-1 19 | OrganizationBinding: 20 | Account: !Ref Account1 21 | Properties: 22 | DisplayName: Topic in eu-west-1 that depends on us-east-1 23 | 24 | Topic2: 25 | Type: AWS::SNS::Topic 26 | DependsOnAccount: 27 | - !Ref Account2 28 | - !Ref Account2 29 | - !Ref Account2 30 | DependsOnRegion: 31 | - us-east-1 32 | - us-east-1 33 | - us-east-1 34 | OrganizationBinding: 35 | Account: !Ref Account1 36 | Properties: 37 | DisplayName: Topic in eu-west-1 that depends on us-east-1 38 | 39 | S3Bucket: 40 | Type: AWS::S3::Bucket 41 | OrganizationBinding: 42 | Account: !Ref Account2 43 | Region: us-east-1 44 | Properties: 45 | BucketName: Bucket in us-east-1 46 | -------------------------------------------------------------------------------- /test/resources/depends-on-account/depends-on-account.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: 3 | 4 | Organization: !Include ./organization.yml 5 | DefaultOrganizationBindingRegion: 'eu-west-1' 6 | 7 | Resources: 8 | 9 | Topic: 10 | Type: AWS::SNS::Topic 11 | DependsOnAccount: !Ref Account2 12 | DependsOnRegion: us-east-1 13 | OrganizationBinding: 14 | Account: !Ref Account1 15 | Properties: 16 | DisplayName: Topic in eu-west-1 that depends on us-east-1 17 | 18 | S3Bucket: 19 | Type: AWS::S3::Bucket 20 | OrganizationBinding: 21 | Account: !Ref Account2 22 | Region: us-east-1 23 | Properties: 24 | BucketName: Bucket in us-east-1 25 | -------------------------------------------------------------------------------- /test/resources/depends-on-account/depends-on-master-account.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: 3 | 4 | Organization: !Include ./organization.yml 5 | DefaultOrganizationBindingRegion: 'eu-west-1' 6 | 7 | Resources: 8 | 9 | Topic: 10 | Type: AWS::SNS::Topic 11 | DependsOnAccount: !Ref MasterAccount 12 | DependsOnRegion: us-east-1 13 | OrganizationBinding: 14 | Account: !Ref Account1 15 | Properties: 16 | DisplayName: Topic in eu-west-1 that depends on us-east-1 17 | 18 | S3Bucket: 19 | Type: AWS::S3::Bucket 20 | OrganizationBinding: 21 | IncludeMasterAccount: true 22 | Region: us-east-1 23 | Properties: 24 | BucketName: Bucket in us-east-1 25 | -------------------------------------------------------------------------------- /test/resources/depends-on-account/depends-on-unknown-account.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: 3 | 4 | Organization: !Include ./organization.yml 5 | DefaultOrganizationBindingRegion: 'eu-west-1' 6 | 7 | Resources: 8 | 9 | Topic: 10 | Type: AWS::SNS::Topic 11 | DependsOnAccount: !Ref AccountUnknown 12 | OrganizationBinding: 13 | Account: !Ref Account1 14 | Properties: 15 | DisplayName: Topic in eu-west-1 that depends on us-east-1 16 | 17 | S3Bucket: 18 | Type: AWS::S3::Bucket 19 | OrganizationBinding: 20 | Account: !Ref Account2 21 | Region: us-east-1 22 | Properties: 23 | BucketName: Bucket in us-east-1 24 | -------------------------------------------------------------------------------- /test/resources/depends-on/depends-on.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: 3 | 4 | Organization: !Include ./organization.yml 5 | DefaultOrganizationBindingRegion: 'eu-west-1' 6 | 7 | Resources: 8 | 9 | Resource1: 10 | Type: AWS::Any::Resource 11 | DependsOn: Dependency 12 | OrganizationBinding: 13 | Account: '*' 14 | Properties: 15 | DisplayName: Resource in all accounts 16 | 17 | Resource2: 18 | Type: AWS::Any::Resource 19 | DependsOn: 20 | - Dependency 21 | OrganizationBinding: 22 | Account: '*' 23 | Properties: 24 | DisplayName: Resource in all accounts 25 | 26 | Dependency: 27 | Type: AWS::Any::Resource 28 | OrganizationBinding: 29 | Account: !Ref Account1 30 | Properties: 31 | BucketName: Resource in only account1 -------------------------------------------------------------------------------- /test/resources/empty-file.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/org-formation/org-formation-cli/e4e1723d3cbe2b2ec9a7ebf56c981a39438547f7/test/resources/empty-file.yml -------------------------------------------------------------------------------- /test/resources/foreach/foreach.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Organization: !Include ./organization.yml 4 | 5 | Parameters: 6 | 7 | someParam: 8 | Type: string 9 | 10 | Resources: 11 | 12 | Topic: 13 | Type: AWS::SNS::Topic 14 | OrganizationBinding: 15 | Region: eu-west-1 16 | IncludeMasterAccount: true 17 | ForeachAccount: 18 | Account: '*' 19 | Properties: 20 | TagInSub: !Sub '${CurrentAccount.Tags.subdomain}.${someParam}.' 21 | TagInGetAtt: !GetAtt CurrentAccount.Tags.subdomain 22 | AccountId: !Ref CurrentAccount 23 | GetAttOfResouce: !GetAtt CurrentAccount.Resources.OtherTopic.Name 24 | 25 | OtherTopic: 26 | Type: AWS::SNS::Topic 27 | OrganizationBinding: 28 | Region: eu-west-1 29 | Account: '*' 30 | Properties: 31 | Name: name -------------------------------------------------------------------------------- /test/resources/invalid-include-invalid-yml.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09-OC 2 | Organization: !Include ./invalid-yml.yml -------------------------------------------------------------------------------- /test/resources/invalid-include-notfound.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09-OC 2 | Organization: !Include ./not-found.yml -------------------------------------------------------------------------------- /test/resources/invalid-version.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: xyz 2 | Organization: -------------------------------------------------------------------------------- /test/resources/invalid-yml.yml: -------------------------------------------------------------------------------- 1 | ::->invalid yml -------------------------------------------------------------------------------- /test/resources/merge-include1.yml: -------------------------------------------------------------------------------- 1 | ProductionAccount1: 2 | Type: OC::ORG::Account 3 | Properties: 4 | RootEmail: production1@myorg.com 5 | AccountName: Production Account 1 6 | 7 | ProductionAccount2: 8 | Type: OC::ORG::Account 9 | Properties: 10 | RootEmail: production2@myorg.com 11 | AccountName: Production Account 2 12 | 13 | ProductionAccount3: 14 | Type: OC::ORG::Account 15 | Properties: 16 | RootEmail: production3@myorg.com 17 | AccountName: Production Account 3 18 | -------------------------------------------------------------------------------- /test/resources/merge-include2.yml: -------------------------------------------------------------------------------- 1 | DevelopmentAccount1: 2 | Type: OC::ORG::Account 3 | Properties: 4 | RootEmail: development1@myorg.com 5 | AccountName: Development Account 1 6 | 7 | DevelopmentAccount2: 8 | Type: OC::ORG::Account 9 | Properties: 10 | RootEmail: development2@myorg.com 11 | AccountName: Development Account 2 12 | 13 | DevelopmentAccount3: 14 | Type: OC::ORG::Account 15 | Properties: 16 | RootEmail: development3@myorg.com 17 | AccountName: Development Account 3 18 | -------------------------------------------------------------------------------- /test/resources/merge-include3.yml: -------------------------------------------------------------------------------- 1 | SharedAccount1: 2 | Type: OC::ORG::Account 3 | Properties: 4 | RootEmail: shared1@myorg.com 5 | AccountName: Shared Account 1 6 | 7 | SharedAccount2: 8 | Type: OC::ORG::Account 9 | Properties: 10 | RootEmail: shared2@myorg.com 11 | AccountName: Shared Account 2 12 | 13 | SharedAccount3: 14 | Type: OC::ORG::Account 15 | Properties: 16 | RootEmail: shared3@myorg.com 17 | AccountName: Shared Account 3 18 | -------------------------------------------------------------------------------- /test/resources/merge.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09-OC 2 | Organization: 3 | MasterAccount: 4 | Type: OC::ORG::MasterAccount 5 | Properties: 6 | AccountName: My Organization Root 7 | AccountId: '123456789012' 8 | <<: !Include 'merge-include1.yml' 9 | <<: !Include "merge-include2.yml" 10 | <<: !Include merge-include3.yml 11 | 12 | -------------------------------------------------------------------------------- /test/resources/missing-organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09-OC -------------------------------------------------------------------------------- /test/resources/missing-version.yml: -------------------------------------------------------------------------------- 1 | Organization: -------------------------------------------------------------------------------- /test/resources/organization-binding/organization-binding-account-id.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: 3 | 4 | Organization: !Include ./organization.yml 5 | 6 | Resources: 7 | 8 | Topic: 9 | Type: AWS::SNS::Topic 10 | OrganizationBinding: 11 | Region: eu-west-1 12 | Account: '123123123123' 13 | Properties: 14 | DisplayName: Physical AccountId as Account Binding Via Parameter 15 | 16 | -------------------------------------------------------------------------------- /test/resources/organization-binding/organization-binding-through-param.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: 3 | 4 | Organization: !Include ./organization.yml 5 | 6 | 7 | Parameters: 8 | 9 | usersAccount: 10 | Type: String 11 | Default: !Ref SharedUsersAccount 12 | 13 | masterAccount: 14 | Type: String 15 | Default: !Ref MasterAccount 16 | 17 | Resources: 18 | 19 | Topic2: 20 | Type: AWS::SNS::Topic 21 | OrganizationBinding: 22 | Region: eu-west-1 23 | Account: !Ref usersAccount 24 | Properties: 25 | DisplayName: Physical AccountId as Account Binding Via Parameter 26 | 27 | Topic: 28 | Type: AWS::SNS::Topic 29 | OrganizationBinding: 30 | Region: eu-west-1 31 | Account: !Ref masterAccount 32 | Properties: 33 | DisplayName: Physical AccountId as Account Binding Via Parameter 34 | 35 | -------------------------------------------------------------------------------- /test/resources/organization-binding/organization.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | 3 | Organization: 4 | MasterAccount: 5 | Type: OC::ORG::MasterAccount 6 | Properties: 7 | AccountId: '000000000000' 8 | AccountName: oc test account 2 9 | 10 | SharedUsersAccount: 11 | Type: OC::ORG::Account 12 | Properties: 13 | AccountName: Shared Users Account 14 | RootEmail: acc1@my.org 15 | 16 | SharedServicesAccount: 17 | Type: OC::ORG::Account 18 | Properties: 19 | AccountName: Shared Services Account 20 | RootEmail: acc2@my.org 21 | 22 | SharedComplianceAccount: 23 | Type: OC::ORG::Account 24 | Properties: 25 | AccountName: Shared Compliance Account 26 | RootEmail: acc3@my.org -------------------------------------------------------------------------------- /test/resources/references/reference-to-account-in-param.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: 3 | 4 | Organization: !Include ./organization.yml 5 | 6 | Parameters: 7 | 8 | masterAccountId: 9 | Type: String 10 | Default: !Ref MasterAccount 11 | 12 | Resources: 13 | 14 | S3Bucket: 15 | Type: AWS::S3::Bucket 16 | OrganizationBinding: 17 | Region: eu-west-1 18 | IncludeMasterAccount: true 19 | Properties: 20 | BucketName: !Sub 'something-${masterAccountId}' 21 | 22 | -------------------------------------------------------------------------------- /test/resources/references/reference-to-multiple.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: 3 | 4 | Organization: !Include ./organization.yml 5 | 6 | Resources: 7 | 8 | Topic: 9 | Type: AWS::SNS::Topic 10 | OrganizationBinding: 11 | Region: eu-west-1 12 | OrganizationalUnit: !Ref OU2 13 | Properties: 14 | DisplayName: Name 15 | 16 | S3Bucket: 17 | Type: AWS::S3::Bucket 18 | OrganizationBinding: 19 | Region: eu-west-1 20 | OrganizationalUnit: !Ref OU1 21 | Properties: 22 | BucketName: !GetAtt Topic.TopicName -------------------------------------------------------------------------------- /test/resources/tasks/build-tasks-duplicate-stackname.yml: -------------------------------------------------------------------------------- 1 | OrganizationUpdate: 2 | Type: update-organization 3 | Template: ./organization.yml 4 | 5 | OrgTemplate: 6 | Type: update-stacks 7 | Template: ./templates/org-template.yml 8 | StackName: stack-name 9 | 10 | OrgTemplate2: 11 | Type: update-stacks 12 | Template: ./templates/org-template.yml 13 | StackName: stack-name -------------------------------------------------------------------------------- /test/resources/tasks/build-tasks-empty.yml: -------------------------------------------------------------------------------- 1 | 2 | OrgTemplate: 3 | Type: update-stacks 4 | Template: ./templates/org-template.yml 5 | StackName: stack-name 6 | -------------------------------------------------------------------------------- /test/resources/tasks/build-tasks-include-empty.yml: -------------------------------------------------------------------------------- 1 | OrganizationUpdate: 2 | Type: update-organization 3 | Template: ./organization.yml 4 | 5 | Include: 6 | Type: include 7 | Path: ./build-tasks-empty.yml 8 | -------------------------------------------------------------------------------- /test/resources/tasks/build-tasks-include-with-duplicate-nested.yml: -------------------------------------------------------------------------------- 1 | OrganizationUpdate: 2 | Type: update-organization 3 | Template: ./organization.yml 4 | 5 | Include: 6 | Type: include 7 | Path: ./include1.yml 8 | 9 | Template: 10 | Type: update-stacks 11 | Template: ./templates/org-template.yml 12 | StackName: stack-name-3 13 | -------------------------------------------------------------------------------- /test/resources/tasks/build-tasks-include-with-duplicate.yml: -------------------------------------------------------------------------------- 1 | OrganizationUpdate: 2 | Type: update-organization 3 | Template: ./organization.yml 4 | 5 | Include: 6 | Type: include 7 | Path: ./include1.yml 8 | 9 | Include2: 10 | Type: include 11 | Path: ./include-include1.yml -------------------------------------------------------------------------------- /test/resources/tasks/build-tasks-include-with-update-org.yml: -------------------------------------------------------------------------------- 1 | OrganizationUpdate: 2 | Type: update-organization 3 | Template: ./organization.yml 4 | 5 | Include: 6 | Type: include 7 | Path: ./build-tasks-include-empty.yml 8 | -------------------------------------------------------------------------------- /test/resources/tasks/build-tasks-param-account-ref.yml: -------------------------------------------------------------------------------- 1 | OrganizationUpdate: 2 | Type: update-organization 3 | Template: ./organization.yml 4 | 5 | StackParamAccount1Ref: 6 | Type: update-stacks 7 | Template: ./templates/cfn-template-param.yml 8 | StackName: stack-name 9 | Parameters: 10 | param: !Ref Account1 11 | 12 | 13 | StackParamMasterAccountRef: 14 | Type: update-stacks 15 | Template: ./templates/cfn-template-param.yml 16 | StackName: stack-name-2 17 | Parameters: 18 | param: !Ref MasterAccount 19 | -------------------------------------------------------------------------------- /test/resources/tasks/build-tasks.yml: -------------------------------------------------------------------------------- 1 | OrganizationUpdate: 2 | Type: update-organization 3 | Template: ./organization.yml 4 | 5 | OrgTemplate: 6 | Type: update-stacks 7 | Template: ./templates/org-template.yml 8 | StackName: stack-name 9 | 10 | CfnTemplate: 11 | Type: update-stacks 12 | Template: ./templates/cfn-template.yml 13 | StackName: cfn-template 14 | 15 | Include1: 16 | Type: include 17 | Path: ./include1.yml 18 | 19 | Include2: 20 | Type: include 21 | Path: ./include2.yml 22 | -------------------------------------------------------------------------------- /test/resources/tasks/include-include1.yml: -------------------------------------------------------------------------------- 1 | 2 | Include: 3 | Type: include 4 | Path: ./include1.yml 5 | -------------------------------------------------------------------------------- /test/resources/tasks/include1.yml: -------------------------------------------------------------------------------- 1 | 2 | Template2: 3 | Type: update-stacks 4 | Template: ./templates/org-template.yml 5 | StackName: stack-name-2 6 | 7 | Template3: 8 | Type: update-stacks 9 | Template: ./templates/org-template.yml 10 | StackName: stack-name-3 11 | -------------------------------------------------------------------------------- /test/resources/tasks/include2.yml: -------------------------------------------------------------------------------- 1 | 2 | Template4: 3 | Type: update-stacks 4 | Template: ./templates/org-template.yml 5 | StackName: stack-name-4 6 | 7 | Template5: 8 | Type: update-stacks 9 | Template: ./templates/org-template.yml 10 | StackName: stack-name-5 11 | -------------------------------------------------------------------------------- /test/resources/tasks/task-depends-on-non-existing.yml: -------------------------------------------------------------------------------- 1 | OrganizationUpdate: 2 | Type: update-organization 3 | Skip: true 4 | Template: ./organization.yml 5 | 6 | SomeTask: 7 | Type: update-stacks 8 | DependsOn: NonExistingTask 9 | Template: ./templates/org-template.yml 10 | StackName: stack-name 11 | -------------------------------------------------------------------------------- /test/resources/tasks/templates/cfn-template-param.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | 3 | Parameters: 4 | param: 5 | Description: account in binding will be passed as parameter. 6 | paramWithDefault: 7 | Default: !Ref Account2 8 | Description: account in binding can be passed as parameter otherwise uses default. 9 | 10 | Resources: 11 | Topic: 12 | Type: AWS::SNS::Topic 13 | OrganizationBinding: 14 | Account: 15 | - !Ref param 16 | - !Ref paramWithDefault 17 | Region: eu-central-1 18 | Properties: 19 | DisplayName: Name 20 | 21 | OtherTopic: 22 | Type: AWS::SNS::Topic 23 | DependsOnAccount: !Ref paramWithDefault 24 | OrganizationBinding: 25 | Account: 26 | - !Ref param 27 | Region: eu-central-1 28 | Properties: 29 | DisplayName: Name 30 | 31 | -------------------------------------------------------------------------------- /test/resources/tasks/templates/cfn-template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: 3 | 4 | Resources: 5 | Topic: 6 | Type: AWS::SNS::Topic 7 | Properties: 8 | DisplayName: Name 9 | -------------------------------------------------------------------------------- /test/resources/tasks/templates/org-template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09-OC' 2 | Description: 3 | 4 | Resources: 5 | 6 | Topic: 7 | Type: AWS::SNS::Topic 8 | OrganizationBinding: 9 | Account: !Ref Account1 10 | Properties: 11 | DisplayName: Name 12 | -------------------------------------------------------------------------------- /test/resources/valid-basic.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09-OC 2 | Organization: 3 | MasterAccount: 4 | Type: OC::ORG::MasterAccount 5 | Properties: 6 | AccountName: My Organization Root 7 | AccountId: '123456789012' -------------------------------------------------------------------------------- /test/resources/valid-include.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09-OC 2 | Organization: !Include ./valid-basic.yml -------------------------------------------------------------------------------- /test/resources/valid-regular-cloudformation.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09-OC 2 | Organization: 3 | Root: 4 | Type: OC::ORG::MasterAccount 5 | Properties: 6 | AccountName: My Organization Root 7 | AccountId: '123456789012' 8 | 9 | Resources: 10 | MyDeploymentBucket: 11 | Type: AWS::S3::Bucket 12 | OrganizationBinding: 13 | Account: '*' 14 | Properties: 15 | BucketName: 'my-deployment-deployments' 16 | PublicAccessBlockConfiguration: 17 | BlockPublicAcls: true 18 | BlockPublicPolicy: true 19 | IgnorePublicAcls: true 20 | RestrictPublicBuckets: true 21 | 22 | Outputs: 23 | SlsDeploymentBucketExport: 24 | Value: !Ref MyDeploymentBucket 25 | Export: 26 | Name: my-deployment-bucket 27 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig", 3 | "compilerOptions": { 4 | "noImplicitAny": false, /* Parse in strict mode and emit "use strict" for each source file. */ 5 | "outDir" : ".ts", 6 | "baseUrl": ".." 7 | }, 8 | "include": [ "./**/*"], 9 | "exclude": [], 10 | "typeRoots": [ 11 | "../node_modules/@types" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/unit-tests/cfn-types.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface ICfnRefValue { Ref: string; } 3 | export interface ICfnGetAttValue { 'Fn::GetAtt': string[]; } 4 | export interface ICfnJoinValue { 'Fn::Join': ICfnValue[]; } 5 | export type ICfnValue = string | ICfnRefValue | ICfnGetAttValue | ICfnJoinValue; 6 | export type ICfnParameterType = 'String' | 'Number' | 'List' | 'CommaDelimitedList' | string; 7 | 8 | export interface ICfnParameterWithExport { 9 | ExportAccountId: string; 10 | ExportRegion: string; 11 | ExportName: string; 12 | } 13 | 14 | export interface ICfnParameter { 15 | Type: ICfnParameterType; 16 | Default: string; 17 | Description: string; 18 | } 19 | 20 | export interface ICfnOutput { 21 | Description: string; 22 | Condition: string; 23 | Value: ICfnValue; 24 | Export: { Name: ICfnValue; }; 25 | } 26 | 27 | export interface ICfnResource { 28 | Type: string; 29 | Condition: string; 30 | DependsOn: string; 31 | Properties: Record; 32 | } 33 | 34 | export interface ICfnTemplate { 35 | Parameters: Record; 36 | Resources: Record; 37 | Outputs: Record; 38 | } 39 | -------------------------------------------------------------------------------- /test/unit-tests/commands/print-org.test.ts: -------------------------------------------------------------------------------- 1 | import { Command, Option } from "commander"; 2 | import { PrintOrganizationCommand } from "~commands/print-org"; 3 | 4 | describe('when creating print tasks command', () => { 5 | let command: PrintOrganizationCommand; 6 | let commanderCommand: Command; 7 | let subCommanderCommand: Command; 8 | 9 | beforeEach(() => { 10 | commanderCommand = new Command('root'); 11 | command = new PrintOrganizationCommand(commanderCommand); 12 | subCommanderCommand = commanderCommand.commands[0]; 13 | }); 14 | 15 | test('print org command is created', () => { 16 | expect(command).toBeDefined(); 17 | expect(subCommanderCommand).toBeDefined(); 18 | expect(subCommanderCommand.name()).toBe('print-org'); 19 | }); 20 | 21 | test('print org command has description', () => { 22 | expect(subCommanderCommand).toBeDefined(); 23 | expect(subCommanderCommand.description()).toBeDefined(); 24 | }); 25 | 26 | test('command has required output parameter with default', () => { 27 | const opts: Option[] = subCommanderCommand.options; 28 | const stackNameOpt = opts.find((x) => x.long === '--output'); 29 | expect(stackNameOpt).toBeDefined(); 30 | expect(stackNameOpt.required).toBeTruthy(); 31 | expect(subCommanderCommand.output).toBe('yaml'); 32 | }); 33 | }); -------------------------------------------------------------------------------- /test/unit-tests/test-organizations.ts: -------------------------------------------------------------------------------- 1 | import { AwsOrganization } from '~aws-provider/aws-organization'; 2 | import { AWSAccount } from '~aws-provider/aws-organization-reader'; 3 | 4 | export class TestOrganizations { 5 | public static createBasicOrganization(): AwsOrganization { 6 | const organizationModel = new AwsOrganization(undefined); 7 | organizationModel.accounts = [{Id: '123456789012', ParentId: 'org-root-id', Policies: [], Type : 'Account', Name: 'Account Name', Tags: {tag1: 'val1'}} as unknown as AWSAccount]; 8 | organizationModel.roots = [{Id: 'org-root-id', Policies: [], OrganizationalUnits: []}]; 9 | organizationModel.masterAccount = { Id : '00000000000000', ParentId: 'org-root-id', Policies: [], Type : 'Account', Name: 'Organizational Master Account' } as AWSAccount; 10 | organizationModel.organization = {Id: 'org-id'}; 11 | organizationModel.organizationalUnits = []; 12 | return organizationModel; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/unit-tests/util/aws-config-file: -------------------------------------------------------------------------------- 1 | [default] 2 | output = json 3 | region = us-east-1 4 | 5 | [profile mfa] 6 | source_profile = default 7 | role_arn = arn:aws:iam::123456789012:role/assumable 8 | mfa_serial = arn:aws:iam::123456789012:mfa/virtual 9 | 10 | [profile credential-process] 11 | credential_process = exec-credential-process credential-process 12 | 13 | [profile aws-sso] 14 | sso_start_url = https://11111111.awsapps.com/start 15 | sso_region = us-east-1 16 | sso_account_id = 123456789012 17 | sso_role_name = admin 18 | -------------------------------------------------------------------------------- /test/unit-tests/util/aws-shared-credentials-file: -------------------------------------------------------------------------------- 1 | [default] 2 | aws_access_key_id = KEY 3 | aws_secret_access_key = SECRET 4 | -------------------------------------------------------------------------------- /test/unit-tests/util/resource-util.test.ts: -------------------------------------------------------------------------------- 1 | import { ResourceUtil } from "~util/resource-util"; 2 | 3 | describe('when fixing versions', () => { 4 | test('dates are converted to string using UTC', ()=> { 5 | const obj = { Version : new Date('2020-09-09T00:00:00.000Z') }; 6 | ResourceUtil.FixVersions(obj) 7 | expect(obj.Version).toBe('2020-09-09'); 8 | }); 9 | }); 10 | --------------------------------------------------------------------------------