|
@@ -0,0 +1,112 @@
|
|
|
+######################
|
|
|
+# Access keys
|
|
|
+#
|
|
|
+# For rotation purposes, there are two of these. Delete the oldest one,
|
|
|
+# add a new one (with a higher version number), and then update the output
|
|
|
+#
|
|
|
+# Possible futue improvement:
|
|
|
+# We could specify a pgp_key attribute, and then the secret will be encrypted
|
|
|
+# in both the state file and in the output. If we used the salt PGP key,
|
|
|
+# no user would ever have to see the secret key.
|
|
|
+locals {
|
|
|
+ # The user in this file will only be created for Commercial C2
|
|
|
+ is_commercial = var.aws_partition == "aws-us-gov" ? false : true
|
|
|
+ is_c2 = contains(["045312110490", "816914342178" ], var.aws_account_id)
|
|
|
+ user_count = local.is_commercial && local.is_c2 ? 1 : 0
|
|
|
+}
|
|
|
+
|
|
|
+resource "aws_iam_access_key" "salt-master-v0" {
|
|
|
+ count = local.user_count
|
|
|
+ user = aws_iam_user.salt-master[count.index].name
|
|
|
+}
|
|
|
+
|
|
|
+resource "aws_iam_access_key" "salt-master-v1" {
|
|
|
+ count = local.user_count
|
|
|
+ user = aws_iam_user.salt-master[count.index].name
|
|
|
+}
|
|
|
+
|
|
|
+output access_keys {
|
|
|
+ # Only output the keys if there _are_ keys
|
|
|
+ value = local.user_count == 0 ? null : {
|
|
|
+ "current" = {
|
|
|
+ "aws_access_key_id": aws_iam_access_key.salt-master-v1[0].id
|
|
|
+ "aws_secret_access_key": aws_iam_access_key.salt-master-v1[0].secret
|
|
|
+ },
|
|
|
+ "previous" = {
|
|
|
+ "aws_access_key_id": aws_iam_access_key.salt-master-v0[0].id
|
|
|
+ "aws_secret_access_key": aws_iam_access_key.salt-master-v0[0].secret
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+######################
|
|
|
+# The policy is attached to both the user and the instance profile
|
|
|
+data "aws_iam_policy_document" "salt_master_policy_doc" {
|
|
|
+ statement {
|
|
|
+ sid = "AllowSaltSecretsCommunication"
|
|
|
+ effect = "Allow"
|
|
|
+
|
|
|
+ actions = [
|
|
|
+ "secretsmanager:GetResourcePolicy",
|
|
|
+ "secretsmanager:GetSecretValue",
|
|
|
+ "secretsmanager:DescribeSecret",
|
|
|
+ "secretsmanager:ListSecretVersionIds"
|
|
|
+ ]
|
|
|
+
|
|
|
+ resources = [
|
|
|
+ "arn:${var.aws_partition}:secretsmanager:*:*:secret:saltmaster/*"
|
|
|
+ ]
|
|
|
+ }
|
|
|
+
|
|
|
+ statement {
|
|
|
+ sid = "AllowAssumeRole"
|
|
|
+ effect = "Allow"
|
|
|
+
|
|
|
+ actions = [
|
|
|
+ "sts:AssumeRole"
|
|
|
+ ]
|
|
|
+
|
|
|
+ resources = [
|
|
|
+ "arn:${var.aws_partition}:iam::*:role/service/salt-master-inventory-role"
|
|
|
+ ]
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+resource "aws_iam_policy" "salt-master" {
|
|
|
+ count = local.user_count
|
|
|
+ name = "salt_master_sm"
|
|
|
+ path = "/"
|
|
|
+ policy = data.aws_iam_policy_document.salt_master_policy_doc.json
|
|
|
+}
|
|
|
+
|
|
|
+######################
|
|
|
+# the user
|
|
|
+#
|
|
|
+# Note: CIS requires that policies _NOT_ be directly attached to a user. Users must
|
|
|
+# be members of groups, and those groups can have policies.
|
|
|
+resource "aws_iam_user" "salt-master" {
|
|
|
+ count = local.user_count
|
|
|
+ name = "salt-master"
|
|
|
+ path = "/instance/"
|
|
|
+
|
|
|
+ tags = merge(var.standard_tags, var.tags)
|
|
|
+}
|
|
|
+
|
|
|
+resource "aws_iam_group" "salt-master" {
|
|
|
+ count = local.user_count
|
|
|
+ name = "salt-master"
|
|
|
+ path = "/instance/"
|
|
|
+}
|
|
|
+
|
|
|
+resource "aws_iam_user_group_membership" "salt-master" {
|
|
|
+ count = local.user_count
|
|
|
+ user = aws_iam_user.salt-master[count.index].name
|
|
|
+
|
|
|
+ groups = [ aws_iam_group.salt-master[count.index].name ]
|
|
|
+}
|
|
|
+
|
|
|
+resource "aws_iam_group_policy_attachment" "salt-master-group" {
|
|
|
+ count = local.user_count
|
|
|
+ group = aws_iam_group.salt-master[count.index].name
|
|
|
+ policy_arn = aws_iam_policy.salt-master[count.index].arn
|
|
|
+}
|