Skip to content

Cloudformation bulk import onto SG Platform #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,31 @@ Migrate workloads from other platforms to [StackGuardian Platform](https://app.s

## Supported platforms for migration

- Terraform Cloud
- [Terraform Cloud](../cloudformation/transformer/terraform-cloud/README.md)
- [Cloudformation Stacks](../cloudformation/transformer/cloudformation/README.md)

## Overview

- Extract and transform the workloads from the target platform to StackGuardian Workflows.
- Review the bulk workflow creation payload.
- Run sg-cli with the bulk workflow creation payload.

## Prerequisites
## Common Prerequisites

- An organization on [StackGuardian Platform](https://app.stackguardian.io)
- Optionally, pre-configure VCS, cloud integrations or private runners to use when importing into StackGuardian Platform.
- Terraform
- [sg-cli](https://github.com/StackGuardian/sg-cli/tree/main/shell)
- Other prerequisites mentioned in the README.md for the transformers

### Perform terraform login
Perform `terraform login` to ensure that your local Terraform can interact with your Terraform Cloud/Enterprise account.

### Export the resource definitions and Terraform state

- Choose the transformer and locate the example of `terraform.tfvars.example` and rename it to `terraform.tfvars`.
- Edit terraform.tfvars with appropriate variables.
- Run the following commands:
- Run the commands mentioned in the README.md for the transformers.

```shell
cd transformer/terraform-cloud
terraform init
terraform apply -auto-approve -var-file=terraform.tfvars
```

A new `export` folder should have been created. The `sg-payload.json` file contains the definition for each workflow that will be created for each Terraform Workspace, and the `states` folder contains the files for the Terraform state for each of your workspaces, if the state export was enabled.
A new `export` folder should have been created. The `sg-payload.json` file contains the definition for each workflow that will be created for the resources under the chosen transformer.

After completing the export , edit the `sg-payload.json` file to provide tune each workflow configuration with the following:
### Use the example_payload.jsonc file as a reference and edit the schema of the `sg-payload.json`
Expand Down
33 changes: 33 additions & 0 deletions transformer/cloudformation/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Local .terraform directories
**/.terraform/*

# Terraform lockfile
.terraform.lock.hcl

# .tfstate files
*.tfstate
*.tfstate.*

# Crash log files
crash.log

# Exclude all .tfvars files, which are likely to contain sentitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
*.tfvars

# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json

# Ignore CLI configuration files
.terraformrc
terraform.rc

# _stack_names.json

_stack_names.json
101 changes: 101 additions & 0 deletions transformer/cloudformation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# StackGuardian Migrator

Migrate workloads from other platforms to [StackGuardian Platform](https://app.stackguardian.io).

## Platform for migration

- Cloudformation Stacks

## Overview

- Extract and transform the stacks from AWS cloudformation to StackGuardian Workflows.
- Review the bulk workflow creation payload.
- Run sg-cli with the bulk workflow creation payload.

## Prerequisites

- An organization on [StackGuardian Platform](https://app.stackguardian.io)
- Optionally, pre-configure VCS, cloud integrations or private runners to use when importing into StackGuardian Platform.
- Terraform
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add "AWS account with adequate access where CloudFormation stacks are maintained."

- AWS CLI configured locally.
- AWS account with adequate access where CloudFormation stacks are maintained.
- [sg-cli](https://github.com/StackGuardian/sg-cli/tree/main/shell)


### Export the resource definitions and Terraform state

- Choose the transformer and locate the example of `terraform.tfvars.example` and rename it to `terraform.tfvars`.
- Edit terraform.tfvars with appropriate variables.
- Run the following commands:

```shell
cd transformer/terraform-cloud
terraform init
terraform apply -target=null_resource.get_stack_names
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment what this and the next command does

terraform apply -auto-approve -var-file=terraform.tfvars
```
terraform apply -target=null_resource.get_stack_names , runs an aws cli to list all the stack names in the AWS acount to create _stacks_names.json file existing in the given region during its execution.

terraform apply -auto-approve -var-file=terraform.tfvars this command , creates a data source with all the stack names retrieved during the previous command to create a sg-payload.json.

A new `export` folder should have been created. The `sg-payload.json` file contains the definition for each workflow that will be created for each stack in the given region.

After completing the export , edit the `sg-payload.json` file to provide tune each workflow configuration with the following:
### Use the example_payload.jsonc file as a reference and edit the schema of the `sg-payload.json`
- `DeploymentPlatformConfig` - This is used to authenticate against a cloud provider using a StackGuardian Integration. Create the relevant integration in StackGuardian platform and update `DeploymentPlatformConfig.kind` from the following "AZURE_STATIC", "AWS_STATIC","GCP_STATIC", "AWS_RBAC". Update `DeploymentPlatformConfig.config.integrationId` with "/integrations/INTEGRATION_NAME" and `DeploymentPlatformConfig.config.profileName` with the name of the integration used upon creation.
```
DeploymentPlatformConfig: [
{
"kind": "AWS_RBAC",
"config": {
"integrationId": "/integrations/aws-rbac",
"profileName": "default"
}
}
]
```
- `VCSConfig` - Provide full path to the `repo` like as well the relevant `sourceConfigDestKind` from the following "GITHUB_COM", "BITBUCKET_ORG", "GITLAB_COM", "AZURE_DEVOPS"
- `config.auth`
- `config.isPrivate`

- `ResourceName` - name of your StackGuardian Workflow
- `wfgrpName` - this corresponds to the labelling of workflow group name in the StackGuardian platform
- `Description` - description for the workflows created in the StackGuardian platform
- `Tags` - list of tags for the workflows created in the StackGuardian platform
- `EnvironmentVariables` - environment variables for the workflows created in the StackGuardian platform
- `RunnerConstraints` - Runner description for the workflows in the StackGuardian platform
- Private runners - ```
"RunnerConstraints": {
"type": "private",
"names": [
"sg-runner"
]
}```
- Shared runners - ```
"RunnerConstraints": {
"type": "shared"
}```
- `Approvers` - Approvers for the workflow to run it successfully
- `TerraformConfig` - Terraform configuration for the workflows created in the StackGuardian platform
- `UserSchedules` - Scheduled workflow run configuration for the workflow in the StackGuardian platform
- `MiniSteps` - Ministeps for the workflow to direct the process if the workflow returns an error/success/approval required and workflow chaining

### Bulk import workflows to StackGuardian Platform

- Fetch [sg-cli](https://github.com/StackGuardian/sg-cli.git) and set it up locally (documentation present in repo)
- Run the following commands and pass the `sg-payload.json` as payload (represented below)
- Get your SG API Key here: https://app.stackguardian.io/orchestrator/orgs/<ORG_ID>/settings?tab=api_key

```shell
cd ../../export

export SG_API_TOKEN=<YOUR_SG_API_TOKEN>
wget -q "$(wget -qO- "https://api.github.com/repos/stackguardian/sg-cli/releases/latest" | jq -r '.tarball_url')" -O sg-cli.tar.gz && tar -xf sg-cli.tar.gz && rm -f sg-cli.tar.gz && /bin/cp -rf StackGuardian-sg-cli*/shell/sg-cli . && rm -rfd StackGuardian-sg-cli*

./sg-cli workflow create --bulk --org "<ORG NAME>" -- sg-payload.json
```

if you want to update a workflow with different details, please re-run the sg-cli command with the modified sg-payload.json and your workflow will be updated with the new details, as long as the ResourceName (Workflow name) remains the same.
```shell
./sg-cli workflow create --bulk --org "<ORG NAME>" -- sg-payload.json
```
5 changes: 5 additions & 0 deletions transformer/cloudformation/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data "aws_cloudformation_stack" "resource" {
for_each = { for stack in local.stack_names : stack.Name => stack }

name = each.value.Name
}
92 changes: 92 additions & 0 deletions transformer/cloudformation/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
locals {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Run terraform fmt

stack_names = jsondecode(file("_stack_names.json"))
}
locals {
workflows = [
for stack_name, stack_data in data.aws_cloudformation_stack.resource : {
CLIConfiguration = {
WorkflowGroup = {
name = stack_name
}
}
ResourceName = stack_name
Description = stack_data.description
Tags = stack_data.tags
EnvironmentVariables = [
{
"config" : {
"textValue" : "eu-west-1",
"varName" : "AWS_REGION"
},
"kind" : "PLAIN_TEXT"
}
]
VCSConfig = {}
TerraformConfig = {}
DeploymentPlatformConfig = var.SGDefaultDeploymentPlatformConfig
WfStepsConfig = [
{
name = "CreateChangeset"
mountPoints = []
wfStepTemplateId = "/demo-org/cloudformation:51"
wfStepInputData = {
schemaType = "FORM_JSONSCHEMA"
data = {
cfCapabilities = stack_data.capabilities
cfStackName = stack_name
cfS3TemplateURL = "${var.s3_path}/${stack_name}.yaml"
cfAction = "create-changeset"
}
}
approval = false
},
{
name = "ApplyChangeset"
mountPoints = []
wfStepTemplateId = "/demo-org/cloudformation:51"
wfStepInputData = {
schemaType = "FORM_JSONSCHEMA"
data = {
cfStackName = stack_name
RetainExceptOnCreate = false
cfAction = "apply-changeset"
DisableRollback = stack_data.disable_rollback
}
}
approval = true
}
]
RunnerConstraints = { type = "shared" }
Approvers = var.SGDefaultWfApprovers
WfType = "CUSTOM"
UserSchedules = []
MiniSteps = {
webhooks = {
COMPLETED = [],
ERRORED = []
}
notifications = {
email = {
APPROVAL_REQUIRED = [],
CANCELLED = [],
COMPLETED = [],
ERRORED = []
}
}
wfChaining = {
COMPLETED = [],
ERRORED = []
}
}
GitHubComSync = {
pull_request_opened = {
createWfRun = {
enabled = false
}
}
}
}
]

data = jsonencode(local.workflows)
}
5 changes: 5 additions & 0 deletions transformer/cloudformation/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
provider "aws" {
region = "eu-central-1" # Change to your desired AWS region
}


31 changes: 31 additions & 0 deletions transformer/cloudformation/resources.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
resource "null_resource" "get_stack_names" {
provisioner "local-exec" {
command = <<-EOT
aws cloudformation describe-stacks --query 'Stacks[*].{Name:StackName}' --output json > _stack_names.json
EOT
}

# Trigger the provisioner only once
triggers = {
always_run = "${timestamp()}"
}
}


resource "aws_s3_object" "upload_templates" {
for_each = data.aws_cloudformation_stack.resource

bucket = var.s3Bucket
key = "${var.s3_path}/${each.key}.yaml"
content = each.value.template_body
depends_on = [data.aws_cloudformation_stack.resource]
}

resource "local_file" "data" {
content = local.data
filename = "${path.module}/../../${var.exportPath}/sg-payload-generated.json"
provisioner "local-exec" {
command = "mv ${path.module}/../../${var.exportPath}/sg-payload-generated.json ${path.module}/../../${var.exportPath}/sg-payload.json"
}
depends_on = [aws_s3_object.upload_templates]
}
31 changes: 31 additions & 0 deletions transformer/cloudformation/terraform.tfvars.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Directory to export Terraform files to
exportPath = "export"

# S3 path to uplaoad cloudformation templates
s3_path = ""

# Default aws region
default_region= ""

# Add emails of the users who should approve the terraform plan, since approvalPreApply is set to true
SGDefaultWfApprovers = []

# Prefix for your repo URL
SGDefaultIACVCSRepoPrefix = "https://www.github.com"

# Provide an integration id like /integrations/aws-dev-account or /secrets/my-git-token
SGDefaultVCSAuthIntegrationID = "/integrations/github_com"

# Integration to use to authenticate against your cloud provider
SGDefaultDeploymentPlatformConfig = [
{
"kind" : "AWS_RBAC",
"config" : {
"integrationId" : "/integrations/aws-dev-account",
"profileName" : "default"
}
}
]

# Choose from: GITHUB_COM, BITBUCKET_ORG, GITLAB_COM, AZURE_DEVOPS, GIT_OTHER
SGDefaultSourceConfigDestKind = "GITHUB_COM"
Loading