TerraSnow Enterprise¶
Enables the deployment of AWS resources from ServiceNow via Terraform Enterprise
Overview¶
TerraSnow Enterprise is a collection of scripts that enable the deployment of Terraform resources from a ServiceNow instance via Terraform Enterprise. It was designed to simplify cloud resource consumption at the user level and to operate within a multi-tenant AWS environment.
This project contains a terraform template to deploy a Ngnix reverse proxied, Flask based endpoint that handles Gitlab Tag and Push events by creating a ServiceNow Terraform Module Catalog Item.
Contents¶
Installation¶
The following instructions outline how to install TerraSnow Enterprise using the included terraform deployable host that is maintained in this project’s repo under /scripting_host
.
Assumptions¶
- A working familiarity with terraform module development and terraform based resource deployment within AWS
- A passing understanding of ServiceNow workflows
Requirements¶
- Admin access to the target AWS account
- Latest version of terraform installed locally
- Pre-configured Gitlab instance
- Pre-configured ServiceNow Instance
- A MidServer deployed in the target AWS account that has been associated with the target ServiceNow instance
- Web console access to Terraform Enterprise
NOTE: All of these services can be used with TerraSnow Enterprise in their SaaS form(s) with the exception of the ServiceNow MidServer.
Setup¶
Start by first cloning the TerraSnow Enterprise repo.
NOTE: Configuration management aims to be as consolidated as possible through the use of a config file. However, there are some caveats so please read through this documentation carefully.
Configuration File¶
Terraform Enterprise and ServiceNow environment specific details are stored within a configuration file. These settings are pulled from this configuration automatically and as needed.
This file must be stored in an S3 bucket that is read-accessible by the TerraSnow instance. Additionally it is recommended that this file be stored in an encrypted S3 bucket due to its sensitive nature.
The expected file structure is as follows:
File Name: config.ini
Contents:
[SERVICENOW]
INSTANCE_NAME=
SN_API_USER_NAME=
SN_API_USER_PWD=
TF_CATALOG=
CATEGORY=
TFE_WORKFLOW=
[TERRAFORM_ENTERPRISE]
INSTANCE_NAME=
ATLAS_TOKEN=
ServiceNow¶
Overview of the config.ini
settings for ServiceNow specific information
Value | Description |
---|---|
INSTANCE_NAME | url of the target ServiceNow instance ex: https://mysninstance.com |
SN_API_USER_NAME | user name of the user performing API actions against ServiceNow |
SN_API_USER_PWD | password of the user performing API actions against ServiceNow |
TF_CATALOG | sys_id of the target Catalog |
CATEGORY | sys_id of the target Category |
TFE_WORKFLOW | sys_id of the TF catalog item order workflow |
Terraform enterprise¶
Overview of the config.ini
settings for Terraform Enterprise specific information
Value | Description |
---|---|
INSTANCE_NAME | url of the target TFE instance ex: https://app.terraform.io |
ATLAS_TOKEN | User API access token to create and populate TFE workspaces |
ServiceNow¶
NOTE: These procedures outline installing this project without an associated ServiceNow application and will be built within the global scope. However, all ServiceNow scripts/workflows have been written to work within a scoped application.
MID Server¶
Deploy a mid server into the target AWS environment. This mid server will be making the api calls against TerraSnow in order to deploy resources against terraform enterprise.
API User¶
- Create an account on the ServiceNow instance that has the following roles:
role_name | requirement |
---|---|
admin | place_holder |
api_analytics_read | place_holder |
catalog_editor | place_holder |
catalog | place_holder |
catalog_admin | place_holder |
credential_admin | place_holder |
rest_api_explorer | place_holder |
user_criteria_admin | place_holder |
web_service_admin | place_holder |
- Keep the username and password of this user on hand for addition into the Terrasnow configuration file
Terraform Catalog¶
- Create a new catalog within ServiceNow by using the instructions in the following link or with the ServiceNow shortcut
sc_catalog.list
- Create a category for the terraform resources catalog
- Copy the
sys_id
of the catalog (Retrievable from the sys_id option of the right click context menu in the catalog list view) and update the value ofTF_CATALOG
inconfig.ini
- Copy the
sys_id
of the terraform resources catalog category (retrievable from the sys_id option of the right click context menu in the catalog Categories tab) and update the value ofCATEGORY
inconfig.ini
Order Workflow¶
- Create a new workflow in ServiceNow using the following instructions here
- Create 4 Run Script activities (Core > Utilities > Run Script), link them, and populate them with the following scripts via copy paste:
NOTE: It is useful when troubleshooting to capture Run Script activity content via log message activities during activity transitions.
Order | Script Name | Requires variable replacements |
---|---|---|
1 | CreateWebhookRequestBodies.js | NO |
2 | SendTFEWorkflowCreationRequest.js | YES |
3 | SendTFEVariablesRequest.js | YES |
4 | SendUploadConfigRequest.js | YES |
For the three workflow activities listed here that require variable replacement ensure YOUR_WEBHOOK_URL
and YOUR_MIDSEVER_DNS_NAME
are replaced with environment specific details.
- Once the workflow has been created copy its
sys_id
and update the value ofself.workflow
inconfig.ini
Terraform Enterprise¶
NOTE: Testing and development was done against Terraform Enterprise using a single Organization.
User API Token¶
- Generate an API token for a Terraform Enterprise user:
TFE console > User Settings > Tokens
- Update the value of
ATLAS_TOKEN
inconfig.ini
TerraSnow Instance¶
This instance will perform all the ‘heavy lifting’ when it comes to building the catalog item(s) within ServiceNow as well as the Workspace creation within Terraform Enterprise when the catalog item is ordered.
Deployment¶
NOTE: Successful deployment requires that the environment specific configuration file has been populated with the correct information and uploaded to S3.
- Navigate to the scripting_host folder and create a
terraform.tfvars
file specific to the target AWS env - Configure the local env to target the correct AWS account either via the AWS cli or by modifying the provider block in
main.tf
- Run
terraform apply
- Proceed to the usage section for catalog item creation and gitlab repo configuration.
API Endpoints¶
On successful deployment the instance is configured with the following endpoints:
Endpoint | Description |
---|---|
/ |
Sends 200 regardless of content, used for testing |
/aws-assume-role-webhook |
Listens for AWS assume role data, creates the required TFE credential env vars |
/gitlab-webhook |
Listens for tag update events sent from gitlab and creates the associated SN catalog item |
/tfe-run-webhook |
Listens for workflow run events, uploads the source terraform module to the target workspace to trigger a TFE workflow event |
/variables-webhook |
Listens for ServiceNow variables creation requests, sends associated API call to SN to create the variable |
/workflow-webhook |
Listens for TFE workspace creation events, creates an empty workspace |
Configuration¶
Usage¶
Requirements¶
The Installation procedures have been completed successfully.
Note:
- Module repositories must meet the same requirements as those outlined for addition to the Terraform Module Private Registry
- This project was successfully tested against the watchmaker lx-instance module.
- The source terraform module has a separate
main.tf
andvariables.tf
file. Variables not defined invariables.tf
will not be included in the resulting ServiceNow catalog item.
ServiceNow TF catalog item creation¶
Note: This procedure requires that the TerraSnow installation steps have been completed successfully
- Create a Gitlab repo with the
terraform-<PROVIDER>-<MODULE_NAME>
name format - Add the TerraSnow instance public key to the repo (available at the
https://YOUR_TERRASNOW_INSTANCE/pub-key/key.txt
) and grant the TerraSnow instance read access to the repo. - Add a version tag to the project before commit that follows the PEP 440 standard (ex: 1.0.2)
- Add the TerraSnow instance url as a webhook under
Repo > Settings > Integrations
- Select
Tag push events
andEnable SSL verification
- Paste in the TerraSnow instance gitlab webhook url:
http://YOUR_TERRASNOW_INSTANCE/gitlab-webhook
- Click the
Add Webhook
button to complete
- Select
- Kick off the ServiceNow catalog item build process by either manually triggering the webhook or incrementing the project’s version tag:
git tag -a v0.0.1 -m 'test' && git push origin --tags
- The Terraform resource catalog item should now be available for order via the target ServiceNow instance.
Note: There is an issue with the ServiceNow catalog item OnLoad client scripts associating with their target variables (see the comments in the embedded client scripts for more details). Unfortunately, this is a manual step for now.
Deploying TF resources from ServiceNow¶
Navigate to the ServiceNow Catalog that was created in the installation steps and complete the catalog item request. On order, the workflow should be triggered and a workspace will be created on the target Terraform Enterprise instance.
Current workspace naming convention is the ServiceNow REQ sys_id but this may be updated in a future release
Scripting Host¶
Documentation that outlines the configuration of the terraform deployable scripting host.
Module Input Variables¶
Variable: subnet_id
Description: The target subnet id for the TerraSnow instance
Variable: env_type
Description: Suffix added to the instance name (dev, test, prod, etc.)
Variable: alias_name
Description: Value used in building the instance name and the instance domain name.
Variable: target_r53_zone
Description: Target route 53 zone in which to build the resulting domain name entry.
Variable: pub_access_sg
Description: The security group within the target AWS account that allows public access.
Variable: priv_access_vpc_id
Description: ID of the VPC that provides private access within the target AWS account.
Variable: priv_alb_subnets
Description: List of subnets that are backed by the private ALB.
Variable: subnet_id
Description: The id of the security group in which to place the instance
Variable: sg_allow_inbound_from
Description: Source security group to allow inbound traffic into the instance’s private security group.
Variable: instance_type
Description: AWS instance type (t2.micro, t2.medium, etc.)
Variable: key_name
Description: SSH public key used to login to the TerraSnow instance.
Variable: instance_role
Description: Role to associate with the TerraForm Scripting host instance. Requires read access to the S3 bucket where the TerraSnow configuration file is stored.
Variable: private_gitlab_server
Description: “hostname of the gitlab server. ex: gitlab.mydomain.net. Passed as a variable into the TerraSnow host initialization script. Used to add the gitlab host as a trusted ssh endpoint and enable use of git clone
via SSH.
Outputs¶
Variable: _private_ip
Value: IPv4 IP address
Description: The private IP address of the TerraSnow instance
Variable: aws_assume_role_webhook
Value: https://INSTANCE_FQDN/aws-assume-role-webhook
Description: The AWS assume role API endpoint of the TerraSnow instance
Variable: gitlab_webhook
Value: https://INSTANCE_FQDN/gitlab-webhook
Description: The gitlab webhook endpoint of the TerraSnow instance
Variable: pub_deployment_key
Value: https://INSTANCE_FQDN/pub-key/key.txt
Description: The web accessible path to the public key of the TerraSnow instance. This key is added to the target gitlab repo as a deploy key with read access to enable the TerraSnow instance to successfully git clone
.
Variable: tfe_workflow_webhook
Value: https://INSTANCE_FQDN/workflow-webhook
Description: The Terraform Enterprise workspace API endpoint of the TerraSnow instance.
Variable: sn_variables_webhook
Value: http://INSTANCE_FQDN/variables-webook
Description: The webhook that triggers the ServiceNow catalog item variables.
Overview¶
The included terraform module will deploy the following resources.
Terraform Enterprise Scripting Host¶
Description: An EC2 instance of the size of your choosing (via the instance_type
variable).
Requirements:
- An IAM role that at a minimum has read access to the S3 bucket where the TerraSnow configuration file is stored.
- An AWS environment that has a security group that provides public access. Port 443 is required as all communications done with the TerraSnow api endpoints are over https via the TerraSnow alb.
Application Load balancer¶
Description: Created via the included alb
module. An ALB that proxies http connections from the TerraSnow instance to https. Backed by an AWS issued https certificate.
Requirements: A separate public access security group within the target AWS account.
TerraSnow Initialization Script¶
Description: A bash script that will install and configure the flask application on an EC2 instance.
Requirements: The EC2 instance on which this script is run will require internet access.
API Reference¶
TerraSnow API endpoints¶
Endpoint | Description |
---|---|
/ |
Sends 200 regardless of content, used for testing |
/aws-assume-role-webhook |
Listens for AWS assume role data, creates the required TFE credential env vars |
/gitlab-webhook |
Listens for tag update events sent from gitlab and creates the associated SN catalog item |
/tfe-run-webhook |
Listens for workflow run events, uploads the source terraform module to the target workspace to trigger a TFE workflow event |
/variables-webhook |
Listens for ServiceNow variables creation requests, sends associated API call to SN to create the variable |
/workflow-webhook |
Listens for TFE workspace creation events, creates an empty workspace |
Assume Role¶
Listens for AWS assume role data, and creates the following TFE workspace environment variables:
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY (created with
is_senative=True
) - AWS_DEFAULT_REGION
- AWS_SESSION_TOKEN
Request Syntax
{
"data": [
{
"region": "us-east-1",
"org_name": "MyTFEorg",
"workspace_name": "ws-123456ASDFhjklmn",
"role": "arn:aws:iam::0123456789123:role/target_role",
"duration": "900"
}
]
}
Parameters
- region (string) – [REQUIRED] – Target region for resource creation.
- org_name (string) – [REQUIRED] – Name of the target TFE region
- workspace_name (string) – [REQUIRED] – Id of the target TFE workspace
- role (string) – [REQUIRED] – The target AWS role to assume. This role requires the necessary permissions to deploy the source terraform template in the target account.
- duration (string) – [REQUIRED] – Maps to the
DurationSections
option in boto3’sassume_role
and is subject to the same limitations. Set to 15 minutes by default.
Returns
The response contains the TFE api responses for each environment variable that is created within the target TFE workspace.
{
"access_key_id": "TFE VARIABLE CREATION RESPONSE",
"secret_access_key": "TFE VARIABLE CREATION RESPONSE",
"region": "TFE VARIABLE CREATION RESPONSE",
"aws_session_token": "TFE VARIABLE CREATION RESPONSE"
}
Gitlab¶
Designed to be triggered on Gitlab tag update events. This endpoint triggers a query against the target ServiceNow instance for a catalog item of the source terraform module. If a ServiceNow catalog item is found and its version is less than the current repo’s version tag a new ServiceNow catalog item will be created and the previous version’s catalog item will be disabled, otherwise no actions are taken.
Request Syntax
Expects the standard gitlab tag update request body
Returns
{
"Status": "200"
}
TFE run¶
This endpoint will query the target workspace for the configuration upload url, git clone
the target repo from Gitlab, and upload the resulting zip of your repo to the workspace. Currently workspace creation sets Auto Apply
to true so any change in the configuration will trigger a Plan and Apply events.
Request Syntax
{
"data" : [
{
"project_name": "terraform-aws-lx-instance",
"repo_url": "git@your_gitlab_instance:gitlab.user/terraform-aws-lx-instance.git",
"module_version": "vx.y.z",
"workspace_id": "ws-123456ASDFhjklmn",
"region": "us-east-1"
}
]
}
Parameters
- project_name (string) – [REQUIRED] – Name of your terraform module project.
- repo_url (string) – [REQUIRED] – SSH URI to the target gitlab repo containing your terraform module
- module_version (string) – [REQUIRED] – specific version tag of your repo that you want to associate the workspace with.
- workspace_id (string) – [REQUIRED] – target TFE workspace id
- region (string) – [REQUIRED] – target AWS region in which your terraform resources will be deployed.
Returns
If successful:
{
"Status": "SUCCESS"
}
In the event of an error TerraSnow will return the response given by the TFE instance against it’s call to
PUT https://archivist.terraform.io/v1/object/<UNIQUE OBJECT ID>
Workflow¶
Listens for TFE workspace events, creates an empty TFE workspace and backs it with your source repo and version tag
Request Syntax
{
"data" :
[
{
"region": "us-east-1",
"org_name": "your_tfe_org",
"workspace_name": "your_tfe_workspace_name",
"repo_id": "gitlab.user/tf_project",
"repo_version": "x.y.z",
"action": "CREATE"
}
]
}
Parameters
- region (string) – [REQUIRED] – target AWS region in which the terraform resources will be deployed
- org_name (string) – [REQUIRED] – the target TFE organization name
- workspace_name (string) – [REQUIRED] – the target TFE workspace name
- repo_id (string) – [REQUIRED] – the id of the source terraform module’s repo
- repo_version (string) – [REQUIRED] – the target version tag of the terraform module’s repo
- action (string) – [REQUIRED] – the desired action on the target workspace, accepts CREATE or DELETE
Returns
TerraSnow simply passes back the response to the workspace creation api endpoint from the TFE instance.
From the official TFE workspace api documentation:
{
"data": {
"id": "ws-SihZTyXKfNXUWuUa",
"type": "workspaces",
"attributes": {
"name": "workspace-2",
"environment": "default",
"auto-apply": false,
"locked": false,
"created-at": "2017-11-02T23:55:16.142Z",
"working-directory": null,
"terraform-version": "0.10.8",
"can-queue-destroy-plan": true,
"vcs-repo": {
"identifier": "skierkowski/terraform-test-proj",
"branch": "",
"oauth-token-id": "ot-hmAyP66qk2AMVdbJ",
"ingress-submodules": false
},
"permissions": {
"can-update": true,
"can-destroy": false,
"can-queue-destroy": false,
"can-queue-run": false,
"can-update-variable": false,
"can-lock": false,
"can-read-settings": true
}
},
"relationships": {
"organization": {
"data": {
"id": "my-organization",
"type": "organizations"
}
},
"ssh-key": {
"data": null
},
"latest-run": {
"data": null
}
},
"links": {
"self": "/api/v2/organizations/my-organization/workspaces/workspace-2"
}
}
}
ServiceNow Catalog Item¶
The details below include descriptions of the variables, client scripts, and script includes utilized in each ServiceNow terraform resource catalog item. Unless otherwise stated variables and client scripts are created automatically.
Variables¶
ServiceNow catalog item variables are automatically populated with the default values of their terraform module counterparts. Variables that are defined in the terraform module without a default value are created as required ServiceNow catalog item variables.
The provided terraform module’s variable description is populated in both the ServiceNow variable question text and tool tip.
tfv¶
Type: String
Description: Denotes the prefix given to the variables included in the terraform module’s variables.tf file.
adv_toggle¶
Type: CheckBox
Description: Advanced mode toggle that is used to show/hide catalog item variables that are not marked as required.
Roles¶
Type: Select Box
Description: Used in conjunction with the populateAWSRoleInfoOnLoad.js
client script. Contains the AWS account information for the user’s select role.
gen_aws_role¶
Type: String
Description: Holds the ARN of the role selected from the Roles dropdown. Auto filled via the enableAfterPopulateRolesOnChange.js
OnChange event
gen_AwsAccountInfo¶
Type: Multi Line Text
Description: Used to hold a JSON object of AWS account info. Details on how this information is populated are not currently documented. More information to follow in a later release.
gen_module_version¶
Type: String
Description: The version of the terraform module as provided in the Gitlab repo tag event.
gen_region¶
Type: String
Description: The target region in which AWS resources will be provisioned. Populated via the enableAfterPopulateRolesOnChange.js
OnChange event.
gen_org_name¶
Type: String
Description: The name of the Terraform Enterprise Organization. Currently populated from the TerraSnow configuration file.
Client Scripts¶
This project contains several ServiceNow client scripts contained within the /sn_javascript
directory that support ease of use when ordering a terraform resource catalog item.
createDiaplyToggleOnChange.js¶
Type: OnChange
Associated Variable: adv_toggle
Description: Used to show or hide ‘advanced’/default terraform module options (those variables included in the the terraform module that were provided with default values.)
hideGenericVariablesOnLoad.js¶
Type: OnLoad
Description: Hides variables prefixed with gen_
on the catalog item load event.
populateAWSRoleInfoOnLoad.js¶
Type: OnLoad
Description: invokes the populateAWSRoleInfoScriptInclude
to populate the roles variable dropdown. This variable’s selection value is then passed to TerraSnow via the /aws-assume-role-webhook
endpoint.
enableAfterPopulateRolesOnChange.js¶
Type: OnChange
Associated Variable: Roles
Description: popluates the gen_aws_role, gen_region variables on selection of the AWS role provided in the Roles variable dropdown
Script Includes¶
populateAWSRoleInfoScriptInclude.js¶
Description: Queries a custom table for the ServiceNow user’s associated Active directory group, their default AWS region, and the AWS account ARN that has been associated with that Active Directory group. Returns a JSON object containing this information.
Project Flow Diagrams¶
Terraform Module Creation Workflow¶

ServiceNow Catalog Item Order¶

ServiceNow Catalog Item Creation - Detailed¶

Supported Versions of ServiceNow¶
- Jakarta (tested working)