Recentemente tive um projeto no trabalho envolvendo o Identity Center da AWS (sucessor do Single Sign-On), quis deixar aqui de uma forma mais simples e prática coisas que fui aprendendo.
Para ficar um pouco melhor a visualização do que será feito, elaborei a imagem abaixo:
Falando das etapas:
- Criação de um grupo;
- Adicionar membro ao grupo;
- Criação da Permission Set;
- Adicionar policies na Permission Set;
- Criar o que é chamado Account Assignment;
Algumas explicações básicas:
- Permission Set é a forma que o Identity Center trabalha com permissões, por trás nada mais é que uma role que é atribuída à um grupo/usuário;
- Esse processo que chamamos de Account Assignment nada mais é que criar o vínculo da Permission Set com a conta que você quer (por exemplo, conta de produção, desenvolvimento, etc). Caso você não conheça muito sobre a estrutura do Identity Center, de forma resumida, ele é centralizado, ou seja, todas as minhas permissões para todas as minhas contas irão ficar centralizada em uma conta só dentro do Identity Center, por isso precisamos criar esse vínculo para que ele saiba em qual conta essas permissões se aplicam.
Código
Tentei trazer um exemplo de código que possa ser reutilizado, para ficar um pouco mais elaborado e vocês conseguirem visualizar algo a mais e não ser um exemplo tão simples.
OBS 01: Estou considerando que você já tenha conhecimento de AWS e Terraform, logo suas credenciais/região já devem estar configuradas.
OBS 02: O código só funciona com a versão do provider AWS >= 5.14. Explico melhor sobre no final.
Nós teremos um arquivo de locals
chamado local.tf
que terá:
data "aws_ssoadmin_instances" "my_sso" {}
output "arns" {
value = tolist(data.aws_ssoadmin_instances.my_sso.arns)[0]
}
output "identity_store_id" {
value = tolist(data.aws_ssoadmin_instances.my_sso.identity_store_ids)[0]
}
# sempre vamos acabar precisando utilizar esse id e esse arn em outros lugares
locals {
identity_store_id = tolist(data.aws_ssoadmin_instances.my_sso.identity_store_ids)[0]
identity_store_arn = tolist(data.aws_ssoadmin_instances.my_sso.arns)[0]
}
Nós teremos um outro arquivo chamado user-group.tf
, nesse arquivo nós iremos colocar um exemplo de estrutura de usuários que queremos adicionar:
variable "user_group" {
description = "Create users in Identity Center"
default = {
"kelly.lima" = {
email = "kelly.lima@email.com"
group = ["group-a"]
first_name = "Kelly"
last_name = "Lima"
}
}
}
Um arquivo chamado policies-managed.tf
onde colocaremos policies gerenciadas pela AWS a forma de adicioná-las é diferente das policies personalizadas. Nas gerenciadas nós teremos:
variable "policies_managed" {
description = "Policies Managed (AWS)"
type = list(string)
default = [
"arn:aws:iam::aws:policy/ReadOnlyAccess",
"arn:aws:iam::aws:policy/AWSBillingReadOnlyAccess"
]
}
Esses valores de arn
serão padrão. Você pode pegar esses valores dentro do próprio IAM.
Arquivo de policies personalizadas se chamará policies-custom.tf
e terá:
variable "policy_group_a" {
description = "Policies Custom"
type = list(string)
default = [
"policies-group-a",
"policies-default"
]
}
No exemplo acima, podemos ver que no Identity Center as policies customizadas nós devemos passar o nome, pois o resource aws_ssoadmin_customer_managed_policy_attachment
(que iremos utilizar em breve) ele só aceita nome da policy e não o arn. Nesse caso eu estou considerando que essa policy já foi criada utilizando o resource aws_iam_policy
.
Teremos um arquivo que chamaremos de accounts.tf
onde terá:
variable "accounts_aws" {
description = "Accounts AWS"
default = {
"prod" = {
number = "123456789345"
},
"dev" = {
number = "458456789345"
}
}
}
Este é um exemplo de como poderia ficar várias contas, mas nós iremos considerar apenas a conta "prod" para facilitar.
Agora nós teremos o nosso último arquivo onde iremos construir todo esse processo que temos na imagem do começo, ficaria:
# Criação do Group A
resource "aws_identitystore_group" "group_a" {
identity_store_id = local.identity_store_id
display_name = "group-a"
description = "sso group a"
}
# Adciona os membros baseado no group em var.user_group
resource "aws_identitystore_group_membership" "membership_group_a" {
for_each = { for user in local.group_members : user => aws_identitystore_user.user_sso[user].user_id }
depends_on = [aws_identitystore_user.user_sso]
identity_store_id = local.identity_store_id
group_id = aws_identitystore_group.group_a.group_id
member_id = each.value
}
# Criação da Permission Set
resource "aws_ssoadmin_permission_set" "permission_set_group_a" {
name = "PermissionGroupA"
instance_arn = local.identity_store_arn
description = "Permission Set Custom"
}
# Adiciona as policies managed AWS na Permission Set
resource "aws_ssoadmin_managed_policy_attachment" "policy_managed_group_a" {
instance_arn = local.identity_store_arn
count = length(var.policies_managed)
managed_policy_arn = var.policies_managed[count.index]
permission_set_arn = aws_ssoadmin_permission_set.permission_set_group_a.arn
}
# Adiciona as policies customizadas na Permission Set
resource "aws_ssoadmin_customer_managed_policy_attachment" "policy_custom" {
for_each = {
for policy_key, policy_value in var.policy_group_a :
policy_key => var.policy_group_a[policy_key]
}
instance_arn = local.identity_store_arn
permission_set_arn = aws_ssoadmin_permission_set.permission_set_group_a.arn
customer_managed_policy_reference {
name = each.value
path = "/"
}
}
# Adiciona a Permission Set com o Group A à conta "prod"
resource "aws_ssoadmin_account_assignment" "prod_env" {
for_each = {
for key, key_value in local.permission_set_arns :
value_key => local.permission_set_arns[value_key]
}
instance_arn = local.identity_store_arn
permission_set_arn = each.value
principal_id = aws_identitystore_group.group_a.group_id
principal_type = "GROUP"
target_id = var.accounts_aws["prod"].number
target_type = "AWS_ACCOUNT"
}
locals {
# Aqui você pode colocar outros arns de Permission Sets
permission_set_arns = [aws_ssoadmin_permission_set.permission_set_group_a.arn]
# Deixei esse locals no mesmo arquivo e não no arquivo local.tf apenas para questão didática, ficar mais prático de visualizar
group_members = [
for user, details in var.user_group :
user if contains(details.group, "group-a")
]
}
Alguns pontos:
Como podem ver é utilizado o depends_on
no resource aws_identitystore_group_membership
foi colocado pois o código estava dando um bug na hora do apply, o Terraform reclamava de adicionar um membro que não existia ainda. Há outros problemas similares quando rodamos o destroy envolvendo Permission Sets, em alguns casos ele reclama do estado que está recebendo (espera estado A e recebe B), ao rodar o comando novamente ele consegue finalizar a exclusão do resource, é realmente um bug nos states do Terraform. Tentei utilizar o depends_on
nesse caso também, mas não obtive sucesso, você pode ver melhor sobre nesses links:
- https://github.com/hashicorp/terraform-provider-aws/issues/26757
- https://github.com/hashicorp/terraform-provider-aws/issues/26807
Sobre o aviso que deixo acima da versão ser >= 5.14 é por conta desses bugs, antes da versão 5.14 eles ocorriam com maior frequência, houve várias correções referentes a Permission Set.
Conclusão
Bom, eu tentei ser o mais sucinta possível, espero que tenha ajudado, qualquer coisa só perguntar. Valeu! ✌️
Top comments (0)