-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from komminarlabs/tk/initial-setup
Initial Setup
- Loading branch information
Showing
8 changed files
with
612 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
--- | ||
name: Terraform | ||
|
||
on: | ||
pull_request: | ||
|
||
permissions: | ||
contents: write | ||
pull-requests: write | ||
|
||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
jobs: | ||
fmt-lint-validate: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Setup Terraform | ||
uses: hashicorp/setup-terraform@v2 | ||
|
||
- name: Setup Terraform Linters | ||
uses: terraform-linters/setup-tflint@v4 | ||
with: | ||
github_token: ${{ env.GITHUB_TOKEN }} | ||
|
||
- name: Terraform Format | ||
id: fmt | ||
run: terraform fmt -check -recursive | ||
|
||
- name: Terraform Init | ||
id: init | ||
run: terraform init | ||
|
||
- name: Terraform Validate | ||
id: validate | ||
run: terraform validate -no-color | ||
|
||
- name: Terraform Lint | ||
id: lint | ||
run: tflint --no-color --recursive --format compact | ||
|
||
- uses: actions/github-script@v6 | ||
if: github.event_name == 'pull_request' || always() | ||
with: | ||
github-token: ${{ env.GITHUB_TOKEN }} | ||
script: | | ||
// 1. Retrieve existing bot comments for the PR | ||
const { data: comments } = await github.rest.issues.listComments({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
issue_number: context.issue.number, | ||
}) | ||
const botComment = comments.find(comment => { | ||
return comment.user.type === 'Bot' && comment.body.includes('Terraform Format and Style') | ||
}) | ||
// 2. Prepare format of the comment | ||
const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\` | ||
#### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\` | ||
#### Terraform Lint 📖\`${{ steps.lint.outcome }}\` | ||
#### Terraform Validation 🤖\`${{ steps.validate.outcome }}\` | ||
<details><summary>Validation Output</summary> | ||
\`\`\`\n | ||
${{ steps.validate.outputs.stdout }} | ||
\`\`\` | ||
</details>`; | ||
// 3. If we have a comment, update it, otherwise create a new one | ||
if (botComment) { | ||
github.rest.issues.updateComment({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
comment_id: botComment.id, | ||
body: output | ||
}) | ||
} else { | ||
github.rest.issues.createComment({ | ||
issue_number: context.issue.number, | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
body: output | ||
}) | ||
} | ||
tfsec: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Terraform security scan | ||
uses: aquasecurity/tfsec-action@v1.0.3 | ||
with: | ||
github_token: ${{ env.GITHUB_TOKEN }} | ||
soft_fail: false | ||
|
||
- name: Terraform pr commenter | ||
uses: aquasecurity/tfsec-pr-commenter-action@v1.3.1 | ||
with: | ||
github_token: ${{ env.GITHUB_TOKEN }} | ||
tfsec_args: --concise-output --force-all-dirs | ||
|
||
checkov: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Check out code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Run Checkov | ||
uses: bridgecrewio/checkov-action@v12.2577.0 | ||
with: | ||
container_user: 1000 | ||
directory: "/" | ||
download_external_modules: false | ||
framework: terraform | ||
output_format: sarif | ||
quiet: true | ||
skip_check: "CKV_TF_1,CKV_AWS_108,CKV_AWS_109,CKV_AWS_111,CKV_AWS_356" | ||
soft_fail: false | ||
|
||
docs: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
with: | ||
ref: ${{ github.event.pull_request.head.ref }} | ||
|
||
- name: Render terraform docs inside the README.md and push changes back to PR branch | ||
uses: terraform-docs/gh-actions@v1.0.0 | ||
with: | ||
args: --sort-by required | ||
git-commit-message: "docs(readme): update module usage" | ||
git-push: true | ||
output-file: README.md | ||
output-method: inject | ||
working-dir: . | ||
continue-on-error: true # added this to prevent a PR from a remote fork failing the workflow |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,70 @@ | ||
# terraform-aws-grafana | ||
Terraform module to create and manage Grafana | ||
# terraform-aws-managed-grafana | ||
Terraform module to create and manage Amazon Managed Grafana | ||
|
||
<!-- BEGIN_TF_DOCS --> | ||
## Requirements | ||
|
||
| Name | Version | | ||
|------|---------| | ||
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 | | ||
|
||
## Providers | ||
|
||
| Name | Version | | ||
|------|---------| | ||
| <a name="provider_aws"></a> [aws](#provider\_aws) | n/a | | ||
|
||
## Modules | ||
|
||
No modules. | ||
|
||
## Resources | ||
|
||
| Name | Type | | ||
|------|------| | ||
| [aws_grafana_license_association.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/grafana_license_association) | resource | | ||
| [aws_grafana_role_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/grafana_role_association) | resource | | ||
| [aws_grafana_workspace.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/grafana_workspace) | resource | | ||
| [aws_grafana_workspace_api_key.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/grafana_workspace_api_key) | resource | | ||
| [aws_iam_policy.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | ||
| [aws_iam_role.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | ||
| [aws_iam_role_policy_attachment.data_sources](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | ||
| [aws_iam_role_policy_attachment.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | ||
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | ||
| [aws_iam_policy_document.assume_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | ||
| [aws_iam_policy_document.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | ||
| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | | ||
|
||
## Inputs | ||
|
||
| Name | Description | Type | Default | Required | | ||
|------|-------------|------|---------|:--------:| | ||
| <a name="input_description"></a> [description](#input\_description) | The workspace description | `string` | n/a | yes | | ||
| <a name="input_name"></a> [name](#input\_name) | The Grafana workspace name | `string` | n/a | yes | | ||
| <a name="input_tags"></a> [tags](#input\_tags) | A mapping of tags to assign to the resources | `map(string)` | n/a | yes | | ||
| <a name="input_account_access_type"></a> [account\_access\_type](#input\_account\_access\_type) | The type of account access for the workspace. Valid values are `CURRENT_ACCOUNT` and `ORGANIZATION`. If ORGANIZATION is specified, then organizational\_units must also be present | `string` | `"CURRENT_ACCOUNT"` | no | | ||
| <a name="input_authentication_providers"></a> [authentication\_providers](#input\_authentication\_providers) | The authentication providers for the workspace. Valid values are `AWS_SSO`, `SAML`, or both | `list(string)` | <pre>[<br> "AWS_SSO"<br>]</pre> | no | | ||
| <a name="input_configuration"></a> [configuration](#input\_configuration) | The configuration string for the workspace that you create | `string` | `null` | no | | ||
| <a name="input_data_sources"></a> [data\_sources](#input\_data\_sources) | The data sources for the workspace. Valid values are `AMAZON_OPENSEARCH_SERVICE`, `ATHENA`, `CLOUDWATCH`, `PROMETHEUS`, `REDSHIFT`, `SITEWISE`, `TIMESTREAM`, `XRAY` | `list(string)` | `[]` | no | | ||
| <a name="input_grafana_version"></a> [grafana\_version](#input\_grafana\_version) | Specifies the version of Grafana to support in the new workspace. If not specified, the default version for the `aws_grafana_workspace` resource will be used. See `aws_grafana_workspace` documentation for available options. | `string` | `"8.4"` | no | | ||
| <a name="input_iam_role_arn"></a> [iam\_role\_arn](#input\_iam\_role\_arn) | The arn of the IAM role to use for grafana workspace | `string` | `null` | no | | ||
| <a name="input_license_type"></a> [license\_type](#input\_license\_type) | The type of license for the workspace license association. Valid values are `ENTERPRISE` and `ENTERPRISE_FREE_TRIAL` | `string` | `null` | no | | ||
| <a name="input_network_access_control"></a> [network\_access\_control](#input\_network\_access\_control) | Configuration for network access to your workspace | <pre>object({<br> prefix_list_ids = list(string)<br> vpce_ids = list(string)<br> })</pre> | `null` | no | | ||
| <a name="input_notification_destinations"></a> [notification\_destinations](#input\_notification\_destinations) | The notification destinations. If a data source is specified here, Amazon Managed Grafana will create IAM roles and permissions needed to use these destinations. Must be set to `SNS` | `list(string)` | <pre>[<br> "SNS"<br>]</pre> | no | | ||
| <a name="input_organization_role_name"></a> [organization\_role\_name](#input\_organization\_role\_name) | The role name that the workspace uses to access resources through Amazon Organizations | `string` | `null` | no | | ||
| <a name="input_organizational_units"></a> [organizational\_units](#input\_organizational\_units) | The Amazon Organizations organizational units that the workspace is authorized to use data sources from | `list(string)` | `[]` | no | | ||
| <a name="input_permission_type"></a> [permission\_type](#input\_permission\_type) | The permission type of the workspace. If `SERVICE_MANAGED` is specified, the IAM roles and IAM policy attachments are generated automatically. If `CUSTOMER_MANAGED` is specified, the IAM roles and IAM policy attachments will not be created | `string` | `"SERVICE_MANAGED"` | no | | ||
| <a name="input_role_association"></a> [role\_association](#input\_role\_association) | List of user/group IDs to assocaite to a role | <pre>list(object({<br> group_ids = optional(list(string))<br> role = string<br> user_ids = optional(list(string))<br> }))</pre> | `[]` | no | | ||
| <a name="input_vpc_configuration"></a> [vpc\_configuration](#input\_vpc\_configuration) | The configuration settings for an Amazon VPC that contains data sources for your Grafana workspace to connect to | <pre>object({<br> security_group_ids = list(string)<br> subnet_ids = list(string)<br> })</pre> | `null` | no | | ||
| <a name="input_workspace_api_key"></a> [workspace\_api\_key](#input\_workspace\_api\_key) | List of workspace API Key resources to create | <pre>list(object({<br> name = string<br> role = string<br> seconds_to_live = number<br> }))</pre> | `[]` | no | | ||
|
||
## Outputs | ||
|
||
| Name | Description | | ||
|------|-------------| | ||
| <a name="output_license_expiration"></a> [license\_expiration](#output\_license\_expiration) | If `license_type` is set to `ENTERPRISE`, this is the expiration date of the enterprise license | | ||
| <a name="output_license_free_trial_expiration"></a> [license\_free\_trial\_expiration](#output\_license\_free\_trial\_expiration) | If `license_type` is set to `ENTERPRISE_FREE_TRIAL`, this is the expiration date of the free trial | | ||
| <a name="output_workspace"></a> [workspace](#output\_workspace) | The Grafana workspace details | | ||
| <a name="output_workspace_api_keys"></a> [workspace\_api\_keys](#output\_workspace\_api\_keys) | The workspace API keys created including their attributes | | ||
| <a name="output_workspace_iam_role"></a> [workspace\_iam\_role](#output\_workspace\_iam\_role) | IAM role details of the Grafana workspace | | ||
<!-- END_TF_DOCS --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
provider "aws" { | ||
region = "eu-central-1" | ||
} | ||
|
||
module "example_grafana_workspace" { | ||
source = "../" | ||
name = "default-workspace" | ||
description = "AWS Managed Grafana service example workspace" | ||
account_access_type = "CURRENT_ACCOUNT" | ||
authentication_providers = ["SAML"] | ||
permission_type = "SERVICE_MANAGED" | ||
data_sources = ["ATHENA", "TIMESTREAM", "XRAY"] | ||
|
||
role_association = [ | ||
{ | ||
role = "ADMIN" | ||
group_ids = ["*******"] | ||
}, | ||
{ | ||
role = "EDITOR" | ||
user_ids = ["*******"] | ||
} | ||
] | ||
|
||
workspace_api_key = [ | ||
{ | ||
name = "admin" | ||
role = "ADMIN" | ||
seconds_to_live = 3600 | ||
}, | ||
{ | ||
name = "editor" | ||
role = "EDITOR" | ||
seconds_to_live = 3600 | ||
}, | ||
{ | ||
name = "viewer" | ||
role = "VIEWER" | ||
seconds_to_live = 3600 | ||
} | ||
] | ||
|
||
tags = { | ||
Environment = "development" | ||
Stack = "grafana" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
locals { | ||
create_iam_role = var.iam_role_arn == null ? true : false | ||
|
||
iam_data_source_policies = { | ||
ATHENA = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonGrafanaAthenaAccess" | ||
CLOUDWATCH = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonGrafanaCloudWatchAccess" | ||
REDSHIFT = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonGrafanaRedshiftAccess" | ||
SITEWISE = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AWSIoTSiteWiseReadOnlyAccess" | ||
TIMESTREAM = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonTimestreamReadOnlyAccess" | ||
XRAY = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AWSXrayReadOnlyAccess" | ||
} | ||
} | ||
|
||
data "aws_iam_policy_document" "assume_policy" { | ||
count = local.create_iam_role ? 1 : 0 | ||
|
||
statement { | ||
sid = "GrafanaAssume" | ||
effect = "Allow" | ||
actions = ["sts:AssumeRole"] | ||
|
||
principals { | ||
type = "Service" | ||
identifiers = ["grafana.${data.aws_partition.current.dns_suffix}"] | ||
} | ||
} | ||
} | ||
|
||
data "aws_iam_policy_document" "default" { | ||
count = local.create_iam_role ? 1 : 0 | ||
|
||
dynamic "statement" { | ||
for_each = contains(var.data_sources, "AMAZON_OPENSEARCH_SERVICE") ? { create : true } : {} | ||
|
||
content { | ||
actions = [ | ||
"es:ESHttpGet", | ||
"es:DescribeElasticsearchDomains", | ||
"es:ListDomainNames", | ||
] | ||
resources = ["*"] | ||
} | ||
} | ||
|
||
dynamic "statement" { | ||
for_each = contains(var.data_sources, "AMAZON_OPENSEARCH_SERVICE") ? { create : true } : {} | ||
|
||
content { | ||
actions = ["es:ESHttpGet"] | ||
resources = [ | ||
"arn:${data.aws_partition.current.partition}:es:*:*:domain/*/_msearch*", | ||
"arn:${data.aws_partition.current.partition}:es:*:*:domain/*/_opendistro/_ppl", | ||
] | ||
} | ||
} | ||
|
||
dynamic "statement" { | ||
for_each = contains(var.data_sources, "PROMETHEUS") ? { create : true } : {} | ||
|
||
content { | ||
actions = [ | ||
"aps:ListWorkspaces", | ||
"aps:DescribeWorkspace", | ||
"aps:QueryMetrics", | ||
"aps:GetLabels", | ||
"aps:GetSeries", | ||
"aps:GetMetricMetadata", | ||
] | ||
resources = ["*"] | ||
} | ||
} | ||
|
||
dynamic "statement" { | ||
for_each = contains(var.notification_destinations, "SNS") ? { create : true } : {} | ||
|
||
content { | ||
actions = ["sns:Publish"] | ||
resources = ["arn:${data.aws_partition.current.partition}:sns:*:${data.aws_caller_identity.current.account_id}:grafana*"] | ||
} | ||
} | ||
} | ||
|
||
resource "aws_iam_role" "default" { | ||
count = local.create_iam_role ? 1 : 0 | ||
|
||
name = "GrafanaExecutionRole-${var.name}" | ||
assume_role_policy = data.aws_iam_policy_document.assume_policy[0].json | ||
tags = var.tags | ||
} | ||
|
||
resource "aws_iam_policy" "default" { | ||
count = local.create_iam_role ? 1 : 0 | ||
|
||
name = "GrafanaExecutionRolePolicy-${var.name}" | ||
policy = data.aws_iam_policy_document.default[0].json | ||
tags = var.tags | ||
} | ||
|
||
resource "aws_iam_role_policy_attachment" "data_sources" { | ||
for_each = { for i, v in var.data_sources : v => local.iam_data_source_policies[v] if local.create_iam_role } | ||
|
||
role = aws_iam_role.default[0].name | ||
policy_arn = each.value | ||
} | ||
|
||
resource "aws_iam_role_policy_attachment" "default" { | ||
count = local.create_iam_role ? 1 : 0 | ||
|
||
role = aws_iam_role.default[0].name | ||
policy_arn = aws_iam_policy.default[0].arn | ||
} |
Oops, something went wrong.