Bootstrap Pipelines in a New GitLab Project
To configure Gruntwork Pipelines in a new GitLab project, complete the following steps (which are explained in detail below):
- (If using a self-hosted GitLab instance) Ensure OIDC configuration and JWKS are publicly accessible.
- Create an
infrastructure-liveproject. - Configure machine user tokens for GitLab access, or ensure that the appropriate machine user tokens are set up as project or organization secrets.
- Create
.gruntworkHCL configurations to tell Pipelines how to authenticate in your environments. - Create
.gitlab-ci.ymlto tell your GitLab CI/CD pipeline how to run your pipelines. - Commit and push your changes to your project.
Ensure OIDC configuration and JWKS are publicly accessible
This step only applies if you are using a self-hosted GitLab instance that is not accessible from the public internet. If you are using GitLab.com or a self-hosted instance that is publicly accessible, you can skip this step.
- Follow GitLab's instructions for hosting your OIDC configuration and JWKS in a public location (e.g. S3 Bucket). This is necessary for both Gruntwork and the AWS OIDC provider to access the GitLab OIDC configuration and JWKS when authenticating JWT's generated by your custom instance.
- Note the <ISSUER_URL> (stored as
ci_id_tokens_issuer_urlin yourgitlab.rbfile per GitLab's instructions) generated above for reuse in the next steps.
Creating the infrastructure-live project
Creating an infrastructure-live project is fairly straightforward. First, create a new project using the official GitLab documentation for creating repositories. Name the project something like infrastructure-live and make it private (or internal).
Configuring SCM Access
Pipelines needs the ability to interact with Source Control Management (SCM) platforms to fetch resources (e.g. IaC code, reusable CI/CD code and the Pipelines binary itself).
For GitLab, you'll need to configure SCM access using machine users with appropriate Personal Access Tokens (PATs).
Creating Cloud Resources for Pipelines
To start using Pipelines, you'll need to ensure that requisite cloud resources are provisioned in your cloud provider(s) to start managing your infrastructure with Pipelines.
If you are using the Gruntwork Account Factory, this will be done automatically during onboarding and in the process of vending every new AWS account, so you don't need to worry about this.
Clone your infrastructure-live project repository to your local machine using Git.
If you don't have Git installed, you can install it by following the official guide for Git installation.
For example:
git clone git@gitlab.com:acme/infrastructure-live.git
cd infrastructure-live
To bootstrap your infrastructure-live repository, we'll use Boilerplate to scaffold it with the necessary IaC code to provision the infrastructure necessary for Pipelines to function.
The easiest way to install Boilerplate is to use mise to install it.
If you don't have mise installed, you can install it by following the official guide for mise installation.
mise use -g boilerplate@latest
If you'd rather install a specific version of Boilerplate, you can use the ls-remote command to list the available versions.
mise ls-remote boilerplate
Cloud-specific bootstrap instructions
- AWS
- Azure
The resources that you need provisioned in AWS to start managing resources with Pipelines are:
- An OpenID Connect (OIDC) provider
- An IAM role for Pipelines to assume when running Terragrunt plan commands
- An IAM role for Pipelines to assume when running Terragrunt apply commands
For every account you want Pipelines to manage infrastructure in.
This may seem like a lot to set up, but the content you need to add to your infrastructure-live repository is minimal. The majority of the work will be pulled from a reusable catalog that you'll reference in your infrastructure-live repository.
If you want to peruse the catalog that's used in the bootstrap process, you can take a look at the terragrunt-scale-catalog repository.
The process that we'll follow to get these resources ready for Pipelines is:
- Set up the Terragrunt configurations in your
infrastructure-liverepository for bootstrapping Pipelines in a single AWS account - Use Terragrunt to provision these resources in your AWS account
- (Optionally) Bootstrap additional AWS accounts until all your AWS accounts are ready for Pipelines
Bootstrap your infrastructure-live repository
To bootstrap your infrastructure-live repository, we'll use Boilerplate to scaffold it with the necessary content for Pipelines to function.
boilerplate \
--template-url 'github.com/gruntwork-io/terragrunt-scale-catalog//templates/boilerplate/aws/gitlab/infrastructure-live?ref=v1.1.0' \
--output-folder .
You can just reply y to all the prompts to include dependencies, and accept defaults unless you want to customize something.
Alternatively, you could run Boilerplate non-interactively by passing the --non-interactive flag. You'll need to supply the relevant values for required variables in that case.
e.g.
boilerplate \
--template-url 'github.com/gruntwork-io/terragrunt-scale-catalog//templates/boilerplate/aws/gitlab/infrastructure-live?ref=v1.1.0' \
--output-folder . \
--var 'AccountName=dev' \
--var 'GitLabGroupName=acme' \
--var 'GitLabRepoName=infrastructure-live' \
--var 'GitLabInstanceURL=https://gitlab.com' \
--var 'AWSAccountID=123456789012' \
--var 'AWSRegion=us-east-1' \
--var 'StateBucketName=my-state-bucket' \
--non-interactive
You can also choose to store these values in a YAML file and pass it to Boilerplate using the --var-file flag.
AccountName: dev
GitLabGroupName: acme
GitLabRepoName: infrastructure-live
GitLabInstanceURL: https://gitlab.com
AWSAccountID: 123456789012
AWSRegion: us-east-1
StateBucketName: my-state-bucket
boilerplate \
--template-url 'github.com/gruntwork-io/terragrunt-scale-catalog//templates/boilerplate/aws/gitlab/infrastructure-live?ref=v1.1.0' \
--output-folder . \
--var-file vars.yml \
--non-interactive
If you're using a self-hosted GitLab instance, you'll want to make sure the issuer is set correctly when calling Boilerplate.
boilerplate \
--template-url 'github.com/gruntwork-io/terragrunt-scale-catalog//templates/boilerplate/aws/gitlab/infrastructure-live?ref=v1.1.0' \
--output-folder . \
--var 'AccountName=dev' \
--var 'GitLabGroupName=acme' \
--var 'GitLabRepoName=infrastructure-live' \
--var 'GitLabInstanceURL=https://gitlab.com' \
--var 'AWSAccountID=123456789012' \
--var 'AWSRegion=us-east-1' \
--var 'StateBucketName=my-state-bucket' \
--var 'Issuer=<ISSUER_URL>' \
--non-interactive
Next, install Terragrunt and OpenTofu locally (the .mise.toml file in the root of the repository after scaffolding should already be set to the versions you want for Terragrunt and OpenTofu):
mise install
Provisioning the resources
Once you've set up the Terragrunt configurations, you can use Terragrunt to provision the resources in your AWS account.
Make sure that you're authenticated with AWS locally before proceeding.
You can follow the documentation here to authenticate with the AWS provider. You are advised to choose an authentication method that doesn't require any hard-coded credentials, like assuming an IAM role.
First, make sure that everything is set up correctly by running a plan in the bootstrap directory in name-of-account/_global where name-of-account is the name of the first AWS account you want to bootstrap.
terragrunt run --all --non-interactive --provider-cache --backend-bootstrap plan
We're using the --provider-cache flag here to ensure that we don't re-download the AWS provider on every run by leveraging the Terragrunt Provider Cache Server.
We're using the --backend-bootstrap flag here to tell Terragrunt to bootstrap the OpenTofu backend automatically for the account.
Next, apply the changes to your account.
terragrunt run --all --non-interactive --provider-cache apply
Optional: Bootstrapping additional AWS accounts
If you have multiple AWS accounts, and you want to bootstrap them as well, you can do so by following a similar, but slightly condensed process.
For each additional account you want to bootstrap, you'll use Boilerplate in the root of your infrastructure-live repository to scaffold out the necessary content for just that account.
If you are going to bootstrap more AWS accounts, you'll probably want to commit your existing changes before proceeding.
git add .
git commit -m "Add core Pipelines scaffolding [skip ci]"
The [skip ci] in the commit message is just in-case you push your changes up to your repository at this state, as you don't want to trigger Pipelines yet.
Just like before, you'll use Boilerplate to scaffold out the necessary content for just that account.
boilerplate \
--template-url 'github.com/gruntwork-io/terragrunt-scale-catalog//templates/boilerplate/aws/gitlab/infrastructure-live?ref=v1.1.0' \
--output-folder .
Again, you can just reply y to all the prompts to include dependencies, and accept defaults unless you want to customize something.
Alternatively, you could run Boilerplate non-interactively by passing the --non-interactive flag. You'll need to supply the relevant values for required variables in that case.
e.g.
boilerplate \
--template-url 'github.com/gruntwork-io/terragrunt-scale-catalog//templates/boilerplate/aws/gitlab/account?ref=v1.1.0' \
--output-folder . \
--var 'AccountName=prod' \
--var 'AWSAccountID=987654321012' \
--var 'AWSRegion=us-east-1' \
--var 'StateBucketName=my-prod-state-bucket' \
--var 'GitLabGroupName=acme' \
--var 'GitLabRepoName=infrastructure-live' \
--var 'GitLabInstanceURL=https://gitlab.com' \
--non-interactive
If you prefer to store the values in a YAML file and pass it to Boilerplate using the --var-file flag, you can do so like this:
AccountName: prod
AWSAccountID: 987654321012
AWSRegion: us-east-1
StateBucketName: my-prod-state-bucket
GitLabGroupName: acme
GitLabRepoName: infrastructure-live
GitLabInstanceURL: https://gitlab.com
boilerplate \
--template-url 'github.com/gruntwork-io/terragrunt-scale-catalog//templates/boilerplate/aws/gitlab/account?ref=v1.1.0' \
--output-folder . \
--var-file vars.yml \
--non-interactive
Once you've scaffolded out the additional accounts you want to bootstrap, you can use Terragrunt to provision the resources in each of these accounts.
Make sure that you authenticate to each AWS account you are bootstrapping using AWS credentials for that account before you attempt to provision resources in it.
For each account you want to bootstrap, you'll need to run the following commands:
cd <account-name>/_global/bootstrap
terragrunt run --all --non-interactive --provider-cache --backend-bootstrap plan
terragrunt run --all --non-interactive --provider-cache apply
The resources that you need provisioned in Azure to start managing resources with Pipelines are:
- An Azure Resource Group for OpenTofu state resources
- An Azure Storage Account in that resource group for OpenTofu state storage
- An Azure Storage Container in that storage account for OpenTofu state storage
- An Azure Storage Account in that resource group for OpenTofu state storage
- An Entra ID Application to use for Pipelines plans
- A Flexible Federated Identity Credential for the application to authenticate with your project on any branch
- A Service Principal for the application to be used in role assignments
- A role assignment for the service principal to access the Azure subscription
- A role assignment for the service principal to access the Azure Storage Account
- An Entra ID Application to use for Pipelines applies
- A Federated Identity Credential for the application to authenticate with your project on the deploy branch
- A Service Principal for the application to be used in role assignments
- A role assignment for the service principal to access the Azure subscription
This may seem like a lot to set up, but the content you need to add to your infrastructure-live repository is minimal. The majority of the work will be pulled from a reusable catalog that you'll reference in your infrastructure-live repository.
If you want to peruse the catalog that's used in the bootstrap process, you can take a look at the terragrunt-scale-catalog repository.
The process that we'll follow to get these resources ready for Pipelines is:
- Set up these bootstrap resources by creating some Terragrunt configurations in your
infrastructure-liverepository for bootstrapping Pipelines in a single Azure subscription - Use Terragrunt to provision these resources in your Azure subscription
- Finalizing Terragrunt configurations using the bootstrap resources we just provisioned
- Pull the bootstrapped resources into state, now that we have configured a remote state backend
- (Optionally) Bootstrap additional Azure subscriptions until all your Azure subscriptions are ready for Pipelines
Bootstrap your infrastructure-live repository
To bootstrap your infrastructure-live repository, we'll use Boilerplate to scaffold it with the necessary content for Pipelines to function.
boilerplate \
--template-url 'github.com/gruntwork-io/terragrunt-scale-catalog//templates/boilerplate/azure/gitlab/infrastructure-live?ref=v1.1.0' \
--output-folder .
You can just reply y to all the prompts to include dependencies, and accept defaults unless you want to customize something.
Alternatively, you could run Boilerplate non-interactively by passing the --non-interactive flag. You'll need to supply the relevant values for required variables in that case.
e.g.
boilerplate \
--template-url 'github.com/gruntwork-io/terragrunt-scale-catalog//templates/boilerplate/azure/gitlab/infrastructure-live?ref=v1.1.0' \
--output-folder . \
--var 'AccountName=dev' \
--var 'GitLabGroupName=acme' \
--var 'GitLabRepoName=infrastructure-live' \
--var 'GitLabInstanceURL=https://gitlab.com' \
--var 'SubscriptionName=dev' \
--var 'AzureTenantID=00000000-0000-0000-0000-000000000000' \
--var 'AzureSubscriptionID=11111111-1111-1111-1111-111111111111' \
--var 'AzureLocation=East US' \
--var 'StateResourceGroupName=pipelines-rg' \
--var 'StateStorageAccountName=mysa' \
--var 'StateStorageContainerName=tfstate' \
--non-interactive
You can also choose to store these values in a YAML file and pass it to Boilerplate using the --var-file flag.
AccountName: dev
GitLabGroupName: acme
GitLabRepoName: infrastructure-live
GitLabInstanceURL: https://gitlab.com
SubscriptionName: dev
AzureTenantID: 00000000-0000-0000-0000-000000000000
AzureSubscriptionID: 11111111-1111-1111-1111-111111111111
AzureLocation: East US
StateResourceGroupName: pipelines-rg
StateStorageAccountName: my-storage-account
StateStorageContainerName: tfstate
boilerplate \
--template-url 'github.com/gruntwork-io/terragrunt-scale-catalog//templates/boilerplate/azure/gitlab/infrastructure-live?ref=v1.1.0' \
--output-folder . \
--var-file vars.yml \
--non-interactive
Next, install Terragrunt and OpenTofu locally (the .mise.toml file in the root of the repository after scaffolding should already be set to the versions you want for Terragrunt and OpenTofu):
mise install
Provisioning the resources
Once you've set up the Terragrunt configurations, you can use Terragrunt to provision the resources in your Azure subscription.
If you haven't already, you'll want to authenticate to Azure using the az CLI.
az login
To dynamically configure the Azure provider with a given tenant ID and subscription ID, ensure that you are exporting the following environment variables if you haven't set the values via the az CLI:
ARM_TENANT_IDARM_SUBSCRIPTION_ID
For example:
export ARM_TENANT_ID="00000000-0000-0000-0000-000000000000"
export ARM_SUBSCRIPTION_ID="11111111-1111-1111-1111-111111111111"
First, make sure that everything is set up correctly by running a plan in the subscription directory.
terragrunt run --all --non-interactive --provider-cache plan
We're using the --provider-cache flag here to ensure that we don't re-download the Azure provider on every run to speed up the process by leveraging the Terragrunt Provider Cache Server.
Next, apply the changes to your subscription.
terragrunt run --all --non-interactive --provider-cache --no-stack-generate apply
We're adding the --no-stack-generate flag here, as Terragrunt will already have the requisite stack configurations generated, and we don't want to accidentally overwrite any configurations while we have state stored locally before we pull them into remote state.
Finalizing Terragrunt configurations
Once you've provisioned the resources in your Azure subscription, you can finalize the Terragrunt configurations using the bootstrap resources we just provisioned.
First, edit the root.hcl file in the root of your infrastructure-live repository to leverage the storage account we just provisioned.
locals {
sub_hcl = read_terragrunt_config(find_in_parent_folders("sub.hcl"))
state_resource_group_name = local.sub_hcl.locals.state_resource_group_name
state_storage_account_name = local.sub_hcl.locals.state_storage_account_name
state_storage_container_name = local.sub_hcl.locals.state_storage_container_name
}
# FIXME: Uncomment the code below when you've successfully bootstrapped Pipelines state.
#
# remote_state {
# backend = "azurerm"
# generate = {
# path = "backend.tf"
# if_exists = "overwrite"
# }
# config = {
# resource_group_name = local.state_resource_group_name
# storage_account_name = local.state_storage_account_name
# container_name = local.state_storage_container_name
# key = "${path_relative_to_include()}/tofu.tfstate"
# }
# }
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "azurerm" {
features {}
resource_provider_registrations = "none"
}
provider "azuread" {}
EOF
}
Uncomment the section that defines the remote state backend, so that you can pull the resources provisioned so far into state.
locals {
sub_hcl = read_terragrunt_config(find_in_parent_folders("sub.hcl"))
state_resource_group_name = local.sub_hcl.locals.state_resource_group_name
state_storage_account_name = local.sub_hcl.locals.state_storage_account_name
state_storage_container_name = local.sub_hcl.locals.state_storage_container_name
}
remote_state {
backend = "azurerm"
generate = {
path = "backend.tf"
if_exists = "overwrite"
}
config = {
resource_group_name = local.state_resource_group_name
storage_account_name = local.state_storage_account_name
container_name = local.state_storage_container_name
key = "${path_relative_to_include()}/tofu.tfstate"
}
}
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "azurerm" {
features {}
resource_provider_registrations = "none"
}
provider "azuread" {}
EOF
}
Next, finalize the .gruntwork/environment-<name-of-subscription>.hcl file in the root of your infrastructure-live repository to reference the IDs for the applications we just provisioned.
environment "dev" {
filter {
paths = ["dev/*"]
}
authentication {
azure_oidc {
tenant_id = "00000000-0000-0000-0000-000000000000"
subscription_id = "11111111-1111-1111-1111-111111111111"
plan_client_id = "" # FIXME: Fill in the client ID for the plan application after bootstrapping
apply_client_id = "" # FIXME: Fill in the client ID for the apply application after bootstrapping
}
}
}
You can find the values for the plan_client_id and apply_client_id by running terragrunt stack output in the bootstrap directory in name-of-subscription/bootstrap.
terragrunt stack output
The relevant bits that you want to extract from the stack output are the following:
bootstrap = {
apply_app = {
client_id = "33333333-3333-3333-3333-333333333333"
}
plan_app = {
client_id = "44444444-4444-4444-4444-444444444444"
}
}
You can use those values to set the values for plan_client_id and apply_client_id in the .gruntwork/environment-<name-of-subscription>.hcl file.
Pulling the resources into state
Once you've provisioned the resources in your Azure subscription, you can pull the resources into state using the storage account we just provisioned.
terragrunt run --all --non-interactive --provider-cache --no-stack-generate -- init -migrate-state -force-copy
We're adding the -force-copy flag here to avoid any issues with OpenTofu waiting for an interactive prompt to copy up local state.
Optional: Bootstrapping additional Azure subscriptions
If you have multiple Azure subscriptions, and you want to bootstrap them as well, you can do so by following a similar, but slightly condensed process.
For each additional subscription you want to bootstrap, you'll use Boilerplate in the root of your infrastructure-live repository to scaffold out the necessary content for just that subscription.
If you are going to bootstrap more Azure subscriptions, you'll probably want to commit your existing changes before proceeding.
git add .
git commit -m "Add additional Azure subscriptions [skip ci]"
Just like before, you'll use Boilerplate to scaffold out the necessary content for just that subscription.
boilerplate \
--template-url 'github.com/gruntwork-io/terragrunt-scale-catalog//templates/boilerplate/azure/gitlab/subscription?ref=v1.1.0' \
--output-folder .
Again, you can just reply y to all the prompts to include dependencies, and accept defaults unless you want to customize something.
Alternatively, you could run Boilerplate non-interactively by passing the --non-interactive flag. You'll need to supply the relevant values for required variables in that case.
e.g.
boilerplate \
--template-url 'github.com/gruntwork-io/terragrunt-scale-catalog//templates/boilerplate/azure/gitlab/subscription?ref=v1.1.0' \
--output-folder . \
--var 'AccountName=prod' \
--var 'GitLabGroupName=acme' \
--var 'GitLabRepoName=infrastructure-live' \
--var 'GitLabInstanceURL=https://gitlab.com' \
--var 'SubscriptionName=prod' \
--var 'AzureTenantID=00000000-0000-0000-0000-000000000000' \
--var 'AzureSubscriptionID=99999999-9999-9999-9999-999999999999' \
--var 'AzureLocation=East US' \
--var 'StateResourceGroupName=pipelines-rg' \
--var 'StateStorageAccountName=myprodsa' \
--var 'StateStorageContainerName=tfstate' \
--non-interactive
If you prefer to store the values in a YAML file and pass it to Boilerplate using the --var-file flag, you can do so like this:
AccountName: prod
GitLabGroupName: acme
GitLabRepoName: infrastructure-live
GitLabInstanceURL: https://gitlab.com
SubscriptionName: prod
AzureTenantID: 00000000-0000-0000-0000-000000000000
AzureSubscriptionID: 99999999-9999-9999-9999-999999999999
AzureLocation: East US
StateResourceGroupName: pipelines-rg
StateStorageAccountName: myprodsa
StateStorageContainerName: tfstate
boilerplate \
--template-url 'github.com/gruntwork-io/terragrunt-scale-catalog//templates/boilerplate/azure/gitlab/subscription?ref=v1.1.0' \
--output-folder . \
--var-file vars.yml \
--non-interactive
To avoid issues with the remote state backend not existing yet, you'll want to comment out your remote state backend configurations in your root.hcl file before you start the bootstrap process for these new subscriptions.
locals {
sub_hcl = read_terragrunt_config(find_in_parent_folders("sub.hcl"))
state_resource_group_name = local.sub_hcl.locals.state_resource_group_name
state_storage_account_name = local.sub_hcl.locals.state_storage_account_name
state_storage_container_name = local.sub_hcl.locals.state_storage_container_name
}
# FIXME: Temporarily commented out again, pending successful bootstrap of the new subscription(s).
#
# remote_state {
# backend = "azurerm"
# generate = {
# path = "backend.tf"
# if_exists = "overwrite"
# }
# config = {
# resource_group_name = local.state_resource_group_name
# storage_account_name = local.state_storage_account_name
# container_name = local.state_storage_container_name
# key = "${path_relative_to_include()}/tofu.tfstate"
# }
# }
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "azurerm" {
features {}
resource_provider_registrations = "none"
}
provider "azuread" {}
EOF
}
Just like before, you can use Terragrunt to provision the resources in each of these subscriptions.
For each subscription you want to bootstrap, you'll need to run the following commands:
cd <subscription-name>/_global/bootstrap
terragrunt run --all --non-interactive --provider-cache plan
terragrunt run --all --non-interactive --provider-cache --no-stack-generate apply
We're adding the --no-stack-generate flag here, as Terragrunt will already have the requisite stack configurations generated, and we don't want to accidentally overwrite any configurations while we have state stored locally before we pull them into remote state.
Next, you can pull the resources into state using the storage account we just provisioned.
First, edit the root.hcl file in the root of your infrastructure-live repository to uncomment the remote state backend configurations you commented out earlier.
locals {
sub_hcl = read_terragrunt_config(find_in_parent_folders("sub.hcl"))
state_resource_group_name = local.sub_hcl.locals.state_resource_group_name
state_storage_account_name = local.sub_hcl.locals.state_storage_account_name
state_storage_container_name = local.sub_hcl.locals.state_storage_container_name
}
remote_state {
backend = "azurerm"
generate = {
path = "backend.tf"
if_exists = "overwrite"
}
config = {
resource_group_name = local.state_resource_group_name
storage_account_name = local.state_storage_account_name
container_name = local.state_storage_container_name
key = "${path_relative_to_include()}/tofu.tfstate"
}
}
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "azurerm" {
features {}
resource_provider_registrations = "none"
}
provider "azuread" {}
EOF
}
Next, you can pull the resources into state using the storage account we just provisioned.
terragrunt run --all --non-interactive --provider-cache --no-stack-generate -- init -migrate-state -force-copy
We're adding the -force-copy flag here to avoid any issues with OpenTofu waiting for an interactive prompt to copy up local state.
Finally, we can edit each of the .gruntwork/environment-<name-of-subscription>.hcl files in the root of your infrastructure-live repository to reference the IDs for the applications we just provisioned.
environment "prod" {
filter {
paths = ["prod/*"]
}
authentication {
azure_oidc {
tenant_id = "00000000-0000-0000-0000-000000000000"
subscription_id = "99999999-9999-9999-9999-999999999999"
plan_client_id = "" # FIXME: Fill in the client ID for the plan application after bootstrapping
apply_client_id = "" # FIXME: Fill in the client ID for the apply application after bootstrapping
}
}
}
You can find the values for the plan_client_id and apply_client_id by running terragrunt stack output in the bootstrap directory in name-of-subscription/bootstrap.
terragrunt stack output
The relevant bits that you want to extract from the stack output are the following:
bootstrap = {
apply_app = {
client_id = "55555555-5555-5555-5555-555555555555"
}
plan_app = {
client_id = "66666666-6666-6666-6666-666666666666"
}
}
You can use those values to set the values for plan_client_id and apply_client_id in the .gruntwork/environment-<name-of-subscription>.hcl file.
Commit and push your changes
Commit and push your changes to your repository.
You should include [skip ci] in your commit message here to prevent triggering the Pipelines workflow.
git add .
git commit -m "Add Pipelines GitLab CI workflow [skip ci]"
git push
🚀 You've successfully added Gruntwork Pipelines to your new repository!
Next steps
You have successfully completed the installation of Gruntwork Pipelines in a new repository. Proceed to Deploying your first infrastructure change to begin deploying changes.