Skip to content

Commit

Permalink
Merge pull request #2 from lorengordon/initial-capability
Browse files Browse the repository at this point in the history
  • Loading branch information
lorengordon authored Jan 12, 2023
2 parents b518e3d + c91b84c commit 5fc7c31
Show file tree
Hide file tree
Showing 28 changed files with 545 additions and 45 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ jobs:
release:
needs:
- lint
- test
# The test workflow currently is expected to fail, since neither localstack
# nor moto support the required AWS SSO endpoints
# - test
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand Down
9 changes: 5 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
## repo-template
## terraform-aws-tardigrade-sso-admin

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).

### 1.0.0

**Commit Delta**: N/A
**Commit Delta**: n/a

**Released**: 2023.01.10
**Released**: 2023.01.11

**Summary**:

* Initial release of capability
* Provides initial capability for managing AWS SSO Permission Sets and Account
Assignments
15 changes: 0 additions & 15 deletions CHANGELOG.template.md

This file was deleted.

2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
FROM plus3it/tardigrade-ci:0.24.2
FROM plus3it/tardigrade-ci:0.24.3
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2023 Maintainers of plus3it/repo-template
Copyright 2023 Maintainers of plus3it/terraform-aws-tardigrade-sso-admin

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
64 changes: 41 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,41 @@
# repo-template
Generic repo template for Plus3IT repositories

To use this template:

1. Select the green "Use this template" button, or [click here](https://github.com/plus3it/repo-template/generate).
2. Select the repo Owner, give the repo a name, enter a description, select Public or Private, and click "Create repository from template".
3. Clone the repository and create a new branch.
4. Edit the following files to customize them for the new repository:
* `LICENSE`
* Near the end of the file, edit the date and change the repository name
* `CHANGELOG.template.md`
* Rename to `CHANGELOG.md`, replacing the repo-template changelog
* Edit templated items for the new repo
* `.bumpversion.cfg`
* Edit the version number for the new repo, ask team if not sure what to
start with
* `README.md`
* Replace contents for the new repo
* `.github/`
* Inspect dependabot and workflow files in case changes are needed for
the new repo
5. Commit the changes and open a pull request
# terraform-aws-tardigrade-sso-admin
Terraform module to manage AWS SSO Admin resources, including:

* [AWS SSO Account Assignments](modules/account-assignments)
* [AWS SSO Permission Sets](modules/permission-sets)

<!-- BEGIN TFDOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.30 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.30 |

## Resources

| Name | Type |
|------|------|
| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
| [aws_ssoadmin_instances.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssoadmin_instances) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_sso_admin"></a> [sso\_admin](#input\_sso\_admin) | Object of inputs for SSO Admin resources | <pre>object({<br> account_assignments = optional(any, [])<br> permission_sets = optional(any, [])<br> })</pre> | `{}` | no |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_account_assignments"></a> [account\_assignments](#output\_account\_assignments) | Object of all AWS SSO Account Assignments |
| <a name="output_permission_sets"></a> [permission\_sets](#output\_permission\_sets) | Object of all AWS SSO Permission Sets |

<!-- END TFDOCS -->
38 changes: 38 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module "permission_sets" {
source = "./modules/permission-set"
for_each = { for permission_set in var.sso_admin.permission_sets : permission_set.name => permission_set }

permission_set = merge(
{
instance_arn = local.sso_instance_arn
partition = local.partition
},
each.value
)
}

module "account_assignments" {
source = "./modules/account-assignment"
for_each = { for account_assignment in var.sso_admin.account_assignments : account_assignment.name => account_assignment }

account_assignment = merge(
{
identity_store_id = local.identity_store_id
instance_arn = local.sso_instance_arn
permission_set_arn = try(
module.permission_sets[each.value.permission_set_name].permission_set.arn,
null,
)
},
each.value
)
}

data "aws_ssoadmin_instances" "this" {}
data "aws_partition" "this" {}

locals {
identity_store_id = data.aws_ssoadmin_instances.this.identity_store_ids[0]
sso_instance_arn = data.aws_ssoadmin_instances.this.arns[0]
partition = data.aws_partition.this.partition
}
40 changes: 40 additions & 0 deletions modules/account-assignment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# terraform-aws-tardigrade-sso-admin/modules/account-assignment

Module for managing an AWS SSO Account Assignment

<!-- BEGIN TFDOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.30 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.30 |

## Resources

| Name | Type |
|------|------|
| [aws_identitystore_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/identitystore_group) | data source |
| [aws_identitystore_user.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/identitystore_user) | data source |
| [aws_ssoadmin_instances.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssoadmin_instances) | data source |
| [aws_ssoadmin_permission_set.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssoadmin_permission_set) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_account_assignment"></a> [account\_assignment](#input\_account\_assignment) | Object of inputs for managing an AWS SSO Account Assignment | <pre>object({<br> identity_store_id = optional(string)<br> principal_name = string<br> principal_type = optional(string, "GROUP")<br> permission_set_arn = optional(string)<br> permission_set_name = optional(string)<br> instance_arn = optional(string)<br> target_id = string<br> })</pre> | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_account_assignment"></a> [account\_assignment](#output\_account\_assignment) | Object of attributes for the AWS SSO Account Assignment |

<!-- END TFDOCS -->
59 changes: 59 additions & 0 deletions modules/account-assignment/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
resource "aws_ssoadmin_account_assignment" "this" {
instance_arn = local.sso_instance_arn
permission_set_arn = var.account_assignment.permission_set_arn != null ? var.account_assignment.permission_set_arn : data.aws_ssoadmin_permission_set.this[0].arn

principal_id = var.account_assignment.principal_type == "GROUP" ? data.aws_identitystore_group.this[0].id : data.aws_identitystore_user.this[0].id
principal_type = var.account_assignment.principal_type

target_id = var.account_assignment.target_id
target_type = "AWS_ACCOUNT"
}

data "aws_ssoadmin_permission_set" "this" {
count = var.account_assignment.permission_set_name != null ? 1 : 0

name = var.account_assignment.permission_set_name
instance_arn = local.sso_instance_arn

depends_on = [
# When the permission set is managed in the same tfstate, it will not exist
# during the plan phase until after the first apply. This depends_on forces
# terraform to wait to evaluate the inputs until after the permission set is
# created, even on the first apply, ensuring it will exist when this data source
# is evaluated. See `tests/test-account-assignment` for the setup that will
# trigger the error condition, if this is removed.
var.account_assignment
]
}

data "aws_identitystore_group" "this" {
count = var.account_assignment.principal_type == "GROUP" ? 1 : 0

identity_store_id = local.identity_store_id

filter {
attribute_path = "DisplayName"
attribute_value = var.account_assignment.principal_name
}
}

data "aws_identitystore_user" "this" {
count = var.account_assignment.principal_type == "USER" ? 1 : 0

identity_store_id = local.identity_store_id

filter {
attribute_path = "UserName"
attribute_value = var.account_assignment.principal_name
}
}

data "aws_ssoadmin_instances" "this" {
count = var.account_assignment.identity_store_id == null || var.account_assignment.instance_arn == null ? 1 : 0
}

locals {
# Reduce api calls
identity_store_id = var.account_assignment.identity_store_id != null ? var.account_assignment.identity_store_id : data.aws_ssoadmin_instances.this[0].identity_store_ids[0]
sso_instance_arn = var.account_assignment.instance_arn != null ? var.account_assignment.instance_arn : data.aws_ssoadmin_instances.this[0].arns[0]
}
4 changes: 4 additions & 0 deletions modules/account-assignment/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output "account_assignment" {
description = "Object of attributes for the AWS SSO Account Assignment"
value = aws_ssoadmin_account_assignment.this
}
27 changes: 27 additions & 0 deletions modules/account-assignment/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
variable "account_assignment" {
description = "Object of inputs for managing an AWS SSO Account Assignment"
nullable = false

type = object({
identity_store_id = optional(string)
principal_name = string
principal_type = optional(string, "GROUP")
permission_set_arn = optional(string)
permission_set_name = optional(string)
instance_arn = optional(string)
target_id = string
})

validation {
condition = contains(["GROUP", "USER"], var.account_assignment.principal_type)
error_message = "The value for `principal_type` must be one of: \"GROUP\", \"USER\"."
}

validation {
condition = anytrue([
var.account_assignment.permission_set_arn != null,
var.account_assignment.permission_set_name != null,
])
error_message = "Must set at least one of `permission_set_arn` or `permission_set_name` to a non-null value."
}
}
10 changes: 10 additions & 0 deletions modules/account-assignment/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
terraform {
required_version = ">= 1.3"

required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.30"
}
}
}
38 changes: 38 additions & 0 deletions modules/permission-set/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# terraform-aws-tardigrade-sso-admin/modules/permission-set

Module for managing an AWS SSO Permission Set

<!-- BEGIN TFDOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.30 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.30 |

## Resources

| Name | Type |
|------|------|
| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
| [aws_ssoadmin_instances.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssoadmin_instances) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_permission_set"></a> [permission\_set](#input\_permission\_set) | Object of inputs for managing an AWS SSO Permission Set | <pre>object({<br> name = string<br> description = optional(string)<br> inline_policy = optional(string)<br> instance_arn = optional(string)<br> relay_state = optional(string)<br> partition = optional(string)<br> session_duration = optional(string, "PT1H")<br> tags = optional(map(string))<br> managed_policy_attachments = optional(list(object({<br> policy_name = string<br> policy_path = optional(string, "/")<br> policy_type = optional(string, "AWS")<br> })), [])<br> })</pre> | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_permission_set"></a> [permission\_set](#output\_permission\_set) | Object of attributes for the AWS SSO Permission Set |

<!-- END TFDOCS -->
50 changes: 50 additions & 0 deletions modules/permission-set/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
resource "aws_ssoadmin_permission_set" "this" {
name = var.permission_set.name
description = var.permission_set.description
instance_arn = local.sso_instance_arn
relay_state = var.permission_set.relay_state
session_duration = var.permission_set.session_duration
tags = var.permission_set.tags
}

resource "aws_ssoadmin_permission_set_inline_policy" "this" {
count = var.permission_set.inline_policy != null ? 1 : 0

inline_policy = var.permission_set.inline_policy
instance_arn = local.sso_instance_arn
permission_set_arn = aws_ssoadmin_permission_set.this.arn
}

resource "aws_ssoadmin_managed_policy_attachment" "this" {
for_each = { for attachment in var.permission_set.managed_policy_attachments : "${var.permission_set.name}:${attachment.policy_name}" => attachment if attachment.policy_type == "AWS" }

instance_arn = local.sso_instance_arn
managed_policy_arn = replace("arn:${local.partition}:iam::aws:policy/${each.value.policy_path}/${each.value.policy_name}", "/[/]+/", "/")
permission_set_arn = aws_ssoadmin_permission_set.this.arn
}

resource "aws_ssoadmin_customer_managed_policy_attachment" "this" {
for_each = { for attachment in var.permission_set.managed_policy_attachments : "${var.permission_set.name}:${attachment.policy_name}" => attachment if attachment.policy_type == "CUSTOMER" }

instance_arn = local.sso_instance_arn
permission_set_arn = aws_ssoadmin_permission_set.this.arn

customer_managed_policy_reference {
name = each.value.policy_name
path = each.value.policy_path
}
}

data "aws_partition" "this" {
count = var.permission_set.partition == null ? 1 : 0
}

data "aws_ssoadmin_instances" "this" {
count = var.permission_set.instance_arn == null ? 1 : 0
}

locals {
# Reduce api calls
sso_instance_arn = var.permission_set.instance_arn != null ? var.permission_set.instance_arn : data.aws_ssoadmin_instances.this[0].arns[0]
partition = var.permission_set.partition != null ? var.permission_set.partition : data.aws_partition.this[0].partition
}
Loading

0 comments on commit 5fc7c31

Please sign in to comment.