Skip to content

Commit 1e585e6

Browse files
feat: backstage example
1 parent ca786c2 commit 1e585e6

File tree

17 files changed

+849
-28
lines changed

17 files changed

+849
-28
lines changed

.github/workflows/ci.yaml

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,41 @@
1-
name: ci
2-
permissions:
3-
contents: read
1+
name: CI
42
on:
53
push:
4+
branches: [main]
5+
pull_request:
6+
branches: [main]
67
jobs:
7-
job:
8-
runs-on: ubuntu-22.04
8+
test:
9+
runs-on: ubuntu-latest
910
steps:
10-
- name: checkout code
11-
uses: actions/checkout@v4
12-
- name: terraform validate
11+
- uses: actions/checkout@v4
12+
13+
- uses: hashicorp/setup-terraform@v2
14+
with:
15+
terraform_version: ~1.5
16+
17+
- name: Terraform Version
18+
run: terraform -version
19+
20+
- name: Install terraform-docs
1321
run: |
14-
terraform init -backend=false
15-
terraform validate
22+
WORK_DIR=$(mktemp -d)
23+
curl -Lo ${WORK_DIR}/terraform-docs.tar.gz https://github.com/terraform-docs/terraform-docs/releases/download/v0.16.0/terraform-docs-v0.16.0-$(uname)-amd64.tar.gz
24+
cd ${WORK_DIR}
25+
tar -xzf terraform-docs.tar.gz
26+
chmod +x terraform-docs
27+
mv terraform-docs /usr/local/bin/terraform-docs
28+
- name: Generate docs
29+
run: make docs
30+
31+
- name: Check git diff is clean (all files generated should be committed)
32+
run: git diff --exit-code
33+
34+
- name: Terraform Format Check
35+
run: make fmt-check
36+
37+
- name: Stub Github App credentials (required for validation)
38+
run: cd ./examples/with-backstage && STUB_FILE=1 node create-gh-app/index.js
39+
40+
- name: Terraform Validate
41+
run: make validate

Makefile

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
TF_DIRS = $(patsubst %/main.tf, %, $(shell find . -type d -name .terraform -prune -o -name 'main.tf' -print))
2+
VALIDATE_TF_DIRS = $(addprefix validate-,$(TF_DIRS))
3+
4+
# Generate docs
5+
.PHONY: docs
6+
docs:
7+
# terraform-docs --lockfile=false ./modules/base
8+
terraform-docs --config docs/.terraform-docs.yaml .
9+
terraform-docs --config docs/.terraform-docs-example.yaml .
10+
terraform-docs --config docs/.terraform-docs.yaml ./examples/with-backstage
11+
terraform-docs --config docs/.terraform-docs-example.yaml ./examples/with-backstage
12+
13+
# Format all terraform files
14+
fmt:
15+
terraform fmt -recursive
16+
17+
# Check if all terraform files are formatted
18+
fmt-check:
19+
terraform fmt -recursive -check
20+
21+
# Validate a terraform directories
22+
$(VALIDATE_TF_DIRS): validate-%:
23+
@echo "Validate $*"
24+
terraform -chdir="$*" init -upgrade
25+
terraform -chdir="$*" validate
26+
27+
# Validate all terraform directories
28+
validate: $(VALIDATE_TF_DIRS)
29+
@echo "All validated"

README.md

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
This repo contains an implementation of part of the Humanitec Reference Architecture for an Internal Developer Platform.
44

5+
To install an implementation containing add-ons, follow the separate README. We currently feature these add-ons:
6+
7+
* [Base layer plus Backstage](examples/with-backstage/)
8+
59
![Google Cloud reference architecture Humanitec](docs/images/Reference-Architecture-Google-Cloud-Humanitec.png)
610

711
This repo covers the base layer of the implementation for Google Cloud (GCP).
@@ -68,7 +72,7 @@ The following variables are required and so need to be set:
6872
| `region` | `string` | The GCP region to provision the infrastructure in. | `"us-west1"` |
6973
| `humanitec_org_id` | `string` | The ID of the Humanitec Organization the cluster should be associated with. | `"my-org"` |
7074

71-
There are many other optional inputs that can be set. The full list is described in [Optional input variables](#optional-input-variables).
75+
There are many other optional inputs that can be set. The full list is described in [Inputs](#inputs).
7276

7377
## Verify your result
7478

@@ -118,14 +122,30 @@ Once you are finished with the reference architecture, you can remove all provis
118122
terraform destroy
119123
```
120124

121-
## Advanced usage
122125

123-
### Optional input variables
126+
<!-- BEGIN_TF_DOCS -->
127+
### Requirements
124128

125-
In addition to the 3 required input variables described in [Required input variables](#required-input-variables), this implementation supports many more that change the behavior of the provisioning of infrastructure.
129+
| Name | Version |
130+
|------|---------|
131+
| terraform | >= 1.3.0 |
132+
| google | ~> 5.1 |
133+
| humanitec | ~> 0.13 |
126134

127-
### Tagging & ID generation
135+
### Modules
128136

129-
| Variable | Type | Description | Default |
130-
| --- | --- | --- | --- |
131-
| `humanitec_prefix` | `string` | A prefix that will be attached to all IDs created in Humanitec | `""` |
137+
| Name | Source | Version |
138+
|------|--------|---------|
139+
| base | ./modules/base | n/a |
140+
141+
### Inputs
142+
143+
| Name | Description | Type | Default | Required |
144+
|------|-------------|------|---------|:--------:|
145+
| humanitec\_org\_id | ID of the Humanitec Organization to associate resources with. | `string` | n/a | yes |
146+
| project\_id | GCP Project ID to provision resources in. | `string` | n/a | yes |
147+
| region | GCP Region to provision resources in. | `string` | n/a | yes |
148+
| environment | The environment to associate the reference architecture with. | `string` | `null` | no |
149+
| environment\_type | The environment type to associate the reference architecture with. | `string` | `"development"` | no |
150+
| humanitec\_prefix | A prefix that will be attached to all IDs created in Humanitec. | `string` | `"htc-ref-arch-"` | no |
151+
<!-- END_TF_DOCS -->

docs/.terraform-docs-example.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
formatter: "tfvars hcl"
2+
3+
output:
4+
file: "./terraform.tfvars.example"
5+
mode: replace
6+
template: "{{ .Content }}"
7+
8+
settings:
9+
description: true

docs/.terraform-docs.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
formatter: "markdown table"
2+
3+
output:
4+
file: "./README.md"
5+
6+
sort:
7+
enabled: true
8+
by: required
9+
10+
11+
settings:
12+
anchor: false
13+
indent: 3
14+
hide-empty: true
15+
lockfile: false

examples/with-backstage/README.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# GCP reference architecture with Backstage
2+
3+
Provisions the GCP reference architecture connected to Humanitec and installs Backstage.
4+
5+
## Prerequisites
6+
7+
* The same prerequisites as the [base reference architecture](../../README.md#prerequisites), plus the following items.
8+
* A GitHub organization and permission to create new repositories in it. Go to https://github.com/account/organizations/new to create a new org (the "Free" option is fine). Note: is has to be an organization, a free account is not sufficient.
9+
* Create a classic github personal access token with `repo`, `workflow`, `delete_repo` and `admin:org` scope [here](https://github.com/settings/tokens).
10+
* Set the `GITHUB_TOKEN` environment variable to your token.
11+
```
12+
export GITHUB_TOKEN="my-github-token"
13+
```
14+
* Set the `GITHUB_ORG_ID` environment variable to your GitHub organization ID.
15+
```
16+
export GITHUB_ORG_ID="my-github-org-id"
17+
```
18+
* [Node.js](https://nodejs.org) installed locally.
19+
* Install the GitHub App for Backstage into your GitHub organization using `node create-gh-app/index.js`. Follow the instructions.
20+
* “All repositories” ~> Install
21+
* “Okay, [] was installed on the [] account.” ~> You can close the window and server.
22+
23+
## Usage
24+
25+
Follow the same steps as for the [base layer](../../README.md#usage), applying these modifications:
26+
* Execute `cd ./examples/with-backstage` after cloning the repo. Execute all subsequent commands in this directory.
27+
* In particular, use the `./examples/with-backstage/terraform.tfvars.example` file as the basis for your `terraform.tfvars` file. It defines additional variables needed to setup and configure Backstage.
28+
29+
## Verify your result
30+
31+
Check for the existence of key elements of the backstage module. This is a subset of all elements only. For a complete list of what was installed, review the Terraform code.
32+
33+
1. Perform the [verification steps of the base installation](../../README.md) if you have not already done so.
34+
2. Verify the existence of the Backstage Application in your Humanitec Organization:
35+
```
36+
curl -s https://api.humanitec.io/orgs/${HUMANITEC_ORG}/apps/backstage \
37+
--header "Authorization: Bearer ${HUMANITEC_TOKEN}"
38+
```
39+
This should output a JSON formatted representation of the Application like so:
40+
```
41+
{"id":"backstage","name":"backstage","created_at":"2023-10-02T13:44:27Z","created_by":"s-d3e94a0e-8b53-29f9-b666-27548b7e06e0","envs":[{"id":"development","name":"Development","type":"development"}]}
42+
```
43+
You can also check for the Application in the [Humanitec Platform Orchestrator UI](https://app.humanitec.io).
44+
45+
3. Connect to your GKE cluster via `kubectl`. See the [GKE documentation](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl) or use this command:
46+
```
47+
gcloud container clusters get-credentials --location <my-gcp-region> --name ref-arch
48+
```
49+
4. Get the elements in the newly created Kubernetes namespace:
50+
```
51+
kubectl get all -n backstage-development
52+
```
53+
You should see
54+
- a `deployment`, `replicaset`, running `pod`, and `service` for Backstage
55+
- a `statefulset`, running `pod`, and `service` for PostgreSQL database used by Backstage.
56+
57+
Note: it may take up to ten minutes after the `terraform apply` completed until you actually see those resources. The Backstage application needs to built and deployed via a GitHub action out of the newly created repository in your GitHub organization.
58+
59+
60+
## Cleaning up
61+
62+
Once you are finished with the reference architecture, you can remove all provisioned infrastructure and the resource definitions created in Humanitec with the following:
63+
64+
1. Delete all Humanitec applications scaffolded using Backstage, but not the `backstage` app itself.
65+
66+
2. Follow the [base reference architecture cleanup instructions](../../README.md#cleaning-up).
67+
68+
## Terraform docs
69+
70+
<!-- BEGIN_TF_DOCS -->
71+
### Requirements
72+
73+
| Name | Version |
74+
|------|---------|
75+
| terraform | >= 1.3.0 |
76+
| github | ~> 5.38 |
77+
| google | ~> 5.1 |
78+
| humanitec | ~> 0.13 |
79+
80+
### Providers
81+
82+
| Name | Version |
83+
|------|---------|
84+
| github | ~> 5.38 |
85+
| google | ~> 5.1 |
86+
| google-beta | n/a |
87+
| humanitec | ~> 0.13 |
88+
89+
### Modules
90+
91+
| Name | Source | Version |
92+
|------|--------|---------|
93+
| backstage\_mysql | git::https://github.com/humanitec-architecture/resource-packs-in-cluster.git//humanitec-resource-defs/mysql/basic | n/a |
94+
| backstage\_postgres | git::https://github.com/humanitec-architecture/resource-packs-in-cluster.git//humanitec-resource-defs/postgres/basic | n/a |
95+
| base | ../../modules/base | n/a |
96+
97+
### Resources
98+
99+
| Name | Type |
100+
|------|------|
101+
| [github_actions_organization_secret.backstage_humanitec_token](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_organization_secret) | resource |
102+
| [github_actions_organization_variable.backstage_cloud_provider](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_organization_variable) | resource |
103+
| [github_actions_organization_variable.backstage_gcp_gar_host](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_organization_variable) | resource |
104+
| [github_actions_organization_variable.backstage_gcp_gar_name](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_organization_variable) | resource |
105+
| [github_actions_organization_variable.backstage_gcp_service_account](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_organization_variable) | resource |
106+
| [github_actions_organization_variable.backstage_gcp_workload_identity_provider](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_organization_variable) | resource |
107+
| [github_actions_organization_variable.backstage_humanitec_org_id](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_organization_variable) | resource |
108+
| [github_repository.backstage](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository) | resource |
109+
| [google-beta_google_iam_workload_identity_pool.main](https://registry.terraform.io/providers/hashicorp/google-beta/latest/docs/resources/google_iam_workload_identity_pool) | resource |
110+
| [google-beta_google_iam_workload_identity_pool_provider.main](https://registry.terraform.io/providers/hashicorp/google-beta/latest/docs/resources/google_iam_workload_identity_pool_provider) | resource |
111+
| [google_artifact_registry_repository.repo](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/artifact_registry_repository) | resource |
112+
| [google_project_iam_member.project](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_member) | resource |
113+
| [google_service_account.sa](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account) | resource |
114+
| [google_service_account_iam_member.wif-sa](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account_iam_member) | resource |
115+
| [humanitec_application.backstage](https://registry.terraform.io/providers/humanitec/humanitec/latest/docs/resources/application) | resource |
116+
| [humanitec_resource_definition_criteria.backstage_mysql](https://registry.terraform.io/providers/humanitec/humanitec/latest/docs/resources/resource_definition_criteria) | resource |
117+
| [humanitec_resource_definition_criteria.backstage_postgres](https://registry.terraform.io/providers/humanitec/humanitec/latest/docs/resources/resource_definition_criteria) | resource |
118+
| [humanitec_value.backstage_cloud_provider](https://registry.terraform.io/providers/humanitec/humanitec/latest/docs/resources/value) | resource |
119+
| [humanitec_value.backstage_github_app_client_id](https://registry.terraform.io/providers/humanitec/humanitec/latest/docs/resources/value) | resource |
120+
| [humanitec_value.backstage_github_app_client_secret](https://registry.terraform.io/providers/humanitec/humanitec/latest/docs/resources/value) | resource |
121+
| [humanitec_value.backstage_github_app_id](https://registry.terraform.io/providers/humanitec/humanitec/latest/docs/resources/value) | resource |
122+
| [humanitec_value.backstage_github_app_private_key](https://registry.terraform.io/providers/humanitec/humanitec/latest/docs/resources/value) | resource |
123+
| [humanitec_value.backstage_github_app_webhook_secret](https://registry.terraform.io/providers/humanitec/humanitec/latest/docs/resources/value) | resource |
124+
| [humanitec_value.backstage_github_org_id](https://registry.terraform.io/providers/humanitec/humanitec/latest/docs/resources/value) | resource |
125+
| [humanitec_value.backstage_humanitec_org](https://registry.terraform.io/providers/humanitec/humanitec/latest/docs/resources/value) | resource |
126+
| [humanitec_value.backstage_humanitec_token](https://registry.terraform.io/providers/humanitec/humanitec/latest/docs/resources/value) | resource |
127+
128+
### Inputs
129+
130+
| Name | Description | Type | Default | Required |
131+
|------|-------------|------|---------|:--------:|
132+
| github\_org\_id | GitHub org id | `string` | n/a | yes |
133+
| humanitec\_ci\_service\_user\_token | Humanitec CI Service User Token | `string` | n/a | yes |
134+
| humanitec\_org\_id | Humanitec Organization ID | `string` | n/a | yes |
135+
| project\_id | GCP Project ID to provision resources in. | `string` | n/a | yes |
136+
| region | GCP Region to provision resources in. | `string` | n/a | yes |
137+
| registry\_location | Region of the Google Artifact Registry. | `string` | n/a | yes |
138+
| environment | The environment to associate the reference architecture with. | `string` | `null` | no |
139+
| environment\_type | The environment type to associate the reference architecture with. | `string` | `"development"` | no |
140+
| humanitec\_prefix | A prefix that will be attached to all IDs created in Humanitec. | `string` | `"htc-ref-arch-"` | no |
141+
<!-- END_TF_DOCS -->
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Configure GitHub variables & secrets for Backstage itself and for all scaffolded apps
2+
3+
locals {
4+
github_app_credentials_file = "github-app-credentials.json"
5+
github_app_credentials = jsondecode(file("${path.module}/${local.github_app_credentials_file}"))
6+
github_app_id = local.github_app_credentials["appId"]
7+
github_app_client_id = local.github_app_credentials["clientId"]
8+
github_app_client_secret = local.github_app_credentials["clientSecret"]
9+
github_app_private_key = local.github_app_credentials["privateKey"]
10+
github_webhook_secret = local.github_app_credentials["webhookSecret"]
11+
}
12+
13+
locals {
14+
backstage_repo = "backstage"
15+
}
16+
17+
resource "github_actions_organization_variable" "backstage_cloud_provider" {
18+
variable_name = "CLOUD_PROVIDER"
19+
visibility = "all"
20+
value = "gcp"
21+
}
22+
23+
resource "github_actions_organization_variable" "backstage_gcp_workload_identity_provider" {
24+
variable_name = "GCP_WORKLOAD_IDENTITY_PROVIDER"
25+
visibility = "all"
26+
value = google_iam_workload_identity_pool_provider.main.name
27+
# value = module.gh_oidc.provider_name
28+
}
29+
30+
resource "github_actions_organization_variable" "backstage_gcp_service_account" {
31+
variable_name = "GCP_SERVICE_ACCOUNT"
32+
visibility = "all"
33+
value = google_service_account.sa.email
34+
}
35+
36+
37+
resource "github_actions_organization_variable" "backstage_gcp_gar_host" {
38+
variable_name = "GCP_GAR_HOST"
39+
visibility = "all"
40+
value = local.registry_host
41+
}
42+
43+
44+
resource "github_actions_organization_variable" "backstage_gcp_gar_name" {
45+
variable_name = "GCP_GAR_NAME"
46+
visibility = "all"
47+
value = local.registry_name
48+
}
49+
50+
51+
resource "github_actions_organization_variable" "backstage_humanitec_org_id" {
52+
variable_name = "HUMANITEC_ORG_ID"
53+
visibility = "all"
54+
value = var.humanitec_org_id
55+
}
56+
57+
resource "github_actions_organization_secret" "backstage_humanitec_token" {
58+
secret_name = "HUMANITEC_TOKEN"
59+
visibility = "all"
60+
plaintext_value = var.humanitec_ci_service_user_token
61+
}
62+
63+
# Backstage repository itself
64+
65+
resource "github_repository" "backstage" {
66+
name = local.backstage_repo
67+
description = "Backstage"
68+
69+
visibility = "public"
70+
71+
template {
72+
# TODO: Replace before merging
73+
# owner = "humanitec-architecture"
74+
# repository = "backstage"
75+
owner = "johanneswuerbach"
76+
repository = "humanitec-architecture-backstage"
77+
}
78+
79+
depends_on = [
80+
module.base,
81+
google_artifact_registry_repository.repo,
82+
# module.gh_oidc,
83+
google_iam_workload_identity_pool_provider.main,
84+
humanitec_application.backstage,
85+
humanitec_resource_definition_criteria.backstage_postgres,
86+
github_actions_organization_secret.backstage_humanitec_token,
87+
]
88+
}

0 commit comments

Comments
 (0)