{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "NORG edge routing: the installer IAM user for this account, with the NorgEdgeInstallerFull policy attached and its access key stored in Secrets Manager as norg-edge-installer/access-key.",
  "Parameters": {
    "UserName": {
      "Type": "String",
      "Default": "norg-edge-installer",
      "Description": "Name of the IAM user NORG's installer will use."
    }
  },
  "Resources": {
    "InstallerBoundary": {
      "Type": "AWS::IAM::ManagedPolicy",
      "Properties": {
        "ManagedPolicyName": {
          "Fn::Sub": "${UserName}-boundary"
        },
        "Description": "Permissions boundary for NORG's edge installer user: caps the user at the NorgEdgeInstallerFull grant however its own inline policy is later rewritten.",
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Sid": "Stacks",
              "Effect": "Allow",
              "Action": [
                "cloudformation:CreateStack",
                "cloudformation:UpdateStack",
                "cloudformation:DeleteStack",
                "cloudformation:DescribeStackEvents",
                "cloudformation:DescribeStackResource",
                "cloudformation:DescribeStackResources",
                "cloudformation:DescribeStacks",
                "cloudformation:GetTemplate",
                "cloudformation:ListStackResources"
              ],
              "Resource": {
                "Fn::Sub": "arn:aws:cloudformation:us-east-1:${AWS::AccountId}:stack/norg-edge-*/*"
              }
            },
            {
              "Sid": "StackList",
              "Effect": "Allow",
              "Action": [
                "cloudformation:ListStacks"
              ],
              "Resource": "*"
            },
            {
              "Sid": "GateFunction",
              "Effect": "Allow",
              "Action": [
                "cloudfront:CreateFunction",
                "cloudfront:UpdateFunction",
                "cloudfront:PublishFunction",
                "cloudfront:DeleteFunction",
                "cloudfront:DescribeFunction",
                "cloudfront:GetFunction",
                "cloudfront:TestFunction",
                "cloudfront:ListTagsForResource",
                "cloudfront:TagResource",
                "cloudfront:UntagResource"
              ],
              "Resource": {
                "Fn::Sub": "arn:aws:cloudfront::${AWS::AccountId}:function/norg-edge-*"
              }
            },
            {
              "Sid": "Distribution",
              "Effect": "Allow",
              "Action": [
                "cloudfront:GetDistribution",
                "cloudfront:GetDistributionConfig",
                "cloudfront:UpdateDistribution",
                "cloudfront:ListDistributions",
                "cloudfront:GetCachePolicy",
                "cloudfront:GetOriginRequestPolicy"
              ],
              "Resource": "*"
            },
            {
              "Sid": "Alarms",
              "Effect": "Allow",
              "Action": [
                "cloudwatch:PutMetricAlarm",
                "cloudwatch:DeleteAlarms",
                "cloudwatch:DescribeAlarms"
              ],
              "Resource": {
                "Fn::Sub": "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:norg-edge-*"
              }
            },
            {
              "Sid": "Lambda",
              "Effect": "Allow",
              "Action": [
                "lambda:CreateFunction",
                "lambda:GetFunction",
                "lambda:GetFunctionConfiguration",
                "lambda:PublishVersion",
                "lambda:DeleteFunction",
                "lambda:UpdateFunctionCode",
                "lambda:UpdateFunctionConfiguration",
                "lambda:AddPermission",
                "lambda:RemovePermission",
                "lambda:EnableReplication",
                "lambda:GetPolicy",
                "lambda:TagResource",
                "lambda:ListVersionsByFunction"
              ],
              "Resource": {
                "Fn::Sub": "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:norg-edge-*"
              }
            },
            {
              "Sid": "LambdaQuotas",
              "Effect": "Allow",
              "Action": [
                "lambda:GetAccountSettings",
                "servicequotas:GetServiceQuota"
              ],
              "Resource": "*"
            },
            {
              "Sid": "Roles",
              "Effect": "Allow",
              "Action": [
                "iam:CreateRole",
                "iam:DeleteRole",
                "iam:GetRole",
                "iam:PassRole",
                "iam:PutRolePolicy",
                "iam:DeleteRolePolicy",
                "iam:GetRolePolicy",
                "iam:AttachRolePolicy",
                "iam:DetachRolePolicy",
                "iam:TagRole"
              ],
              "Resource": {
                "Fn::Sub": "arn:aws:iam::${AWS::AccountId}:role/norg-edge-*"
              }
            },
            {
              "Sid": "ServiceLinkedRoles",
              "Effect": "Allow",
              "Action": [
                "iam:CreateServiceLinkedRole",
                "iam:GetRole"
              ],
              "Resource": [
                {
                  "Fn::Sub": "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/replicator.lambda.amazonaws.com/AWSServiceRoleForLambdaReplicator"
                },
                {
                  "Fn::Sub": "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/logger.cloudfront.amazonaws.com/AWSServiceRoleForCloudFrontLogger"
                }
              ]
            },
            {
              "Sid": "Secrets",
              "Effect": "Allow",
              "Action": [
                "secretsmanager:CreateSecret",
                "secretsmanager:DeleteResourcePolicy",
                "secretsmanager:DeleteSecret",
                "secretsmanager:DescribeSecret",
                "secretsmanager:GetResourcePolicy",
                "secretsmanager:GetSecretValue",
                "secretsmanager:PutResourcePolicy",
                "secretsmanager:PutSecretValue",
                "secretsmanager:RemoveRegionsFromReplication",
                "secretsmanager:ReplicateSecretToRegions",
                "secretsmanager:TagResource",
                "secretsmanager:UntagResource",
                "secretsmanager:UpdateSecret"
              ],
              "Resource": {
                "Fn::Sub": "arn:aws:secretsmanager:us-east-1:${AWS::AccountId}:secret:norg-edge-*"
              }
            },
            {
              "Sid": "Schedule",
              "Effect": "Allow",
              "Action": [
                "events:PutRule",
                "events:DeleteRule",
                "events:DescribeRule",
                "events:PutTargets",
                "events:RemoveTargets"
              ],
              "Resource": {
                "Fn::Sub": "arn:aws:events:us-east-1:${AWS::AccountId}:rule/norg-edge-*"
              }
            },
            {
              "Sid": "Logs",
              "Effect": "Allow",
              "Action": [
                "logs:CreateLogGroup",
                "logs:DeleteLogGroup",
                "logs:PutRetentionPolicy",
                "logs:DescribeLogGroups"
              ],
              "Resource": "*"
            },
            {
              "Sid": "ReadRouterLogs",
              "Effect": "Allow",
              "Action": [
                "logs:FilterLogEvents",
                "logs:GetLogEvents",
                "logs:DescribeLogStreams"
              ],
              "Resource": {
                "Fn::Sub": "arn:aws:logs:*:${AWS::AccountId}:log-group:/aws/lambda/us-east-1.norg-edge-*"
              }
            },
            {
              "Sid": "CloudFrontPolicies",
              "Effect": "Allow",
              "Action": [
                "cloudfront:CreateOriginRequestPolicy",
                "cloudfront:DeleteOriginRequestPolicy",
                "cloudfront:CreateCachePolicy",
                "cloudfront:DeleteCachePolicy",
                "cloudfront:ListCachePolicies",
                "cloudfront:ListOriginRequestPolicies"
              ],
              "Resource": "*"
            },
            {
              "Sid": "AccessLogsBucket",
              "Effect": "Allow",
              "Action": [
                "s3:CreateBucket",
                "s3:DeleteBucket",
                "s3:GetBucketAcl",
                "s3:PutBucketAcl",
                "s3:GetBucketOwnershipControls",
                "s3:PutBucketOwnershipControls",
                "s3:PutBucketPublicAccessBlock",
                "s3:PutLifecycleConfiguration",
                "s3:ListBucket",
                "s3:GetObject"
              ],
              "Resource": [
                "arn:aws:s3:::norg-edge-logs-*",
                "arn:aws:s3:::norg-edge-logs-*/*"
              ]
            },
            {
              "Sid": "SelfManagePolicies",
              "Effect": "Allow",
              "Action": [
                "iam:GetUser",
                "iam:GetUserPolicy",
                "iam:ListUserPolicies",
                "iam:ListAttachedUserPolicies",
                "iam:PutUserPolicy",
                "iam:DeleteUserPolicy"
              ],
              "Resource": {
                "Fn::Sub": "arn:aws:iam::${AWS::AccountId}:user/${UserName}"
              }
            }
          ]
        }
      }
    },
    "InstallerUser": {
      "Type": "AWS::IAM::User",
      "Properties": {
        "UserName": {
          "Ref": "UserName"
        },
        "PermissionsBoundary": {
          "Ref": "InstallerBoundary"
        },
        "Policies": [
          {
            "PolicyName": "NorgEdgeInstallerFull",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Sid": "Stacks",
                  "Effect": "Allow",
                  "Action": [
                    "cloudformation:CreateStack",
                    "cloudformation:UpdateStack",
                    "cloudformation:DeleteStack",
                    "cloudformation:DescribeStackEvents",
                    "cloudformation:DescribeStackResource",
                    "cloudformation:DescribeStackResources",
                    "cloudformation:DescribeStacks",
                    "cloudformation:GetTemplate",
                    "cloudformation:ListStackResources"
                  ],
                  "Resource": {
                    "Fn::Sub": "arn:aws:cloudformation:us-east-1:${AWS::AccountId}:stack/norg-edge-*/*"
                  }
                },
                {
                  "Sid": "StackList",
                  "Effect": "Allow",
                  "Action": [
                    "cloudformation:ListStacks"
                  ],
                  "Resource": "*"
                },
                {
                  "Sid": "GateFunction",
                  "Effect": "Allow",
                  "Action": [
                    "cloudfront:CreateFunction",
                    "cloudfront:UpdateFunction",
                    "cloudfront:PublishFunction",
                    "cloudfront:DeleteFunction",
                    "cloudfront:DescribeFunction",
                    "cloudfront:GetFunction",
                    "cloudfront:TestFunction",
                    "cloudfront:ListTagsForResource",
                    "cloudfront:TagResource",
                    "cloudfront:UntagResource"
                  ],
                  "Resource": {
                    "Fn::Sub": "arn:aws:cloudfront::${AWS::AccountId}:function/norg-edge-*"
                  }
                },
                {
                  "Sid": "Distribution",
                  "Effect": "Allow",
                  "Action": [
                    "cloudfront:GetDistribution",
                    "cloudfront:GetDistributionConfig",
                    "cloudfront:UpdateDistribution",
                    "cloudfront:ListDistributions",
                    "cloudfront:GetCachePolicy",
                    "cloudfront:GetOriginRequestPolicy"
                  ],
                  "Resource": "*"
                },
                {
                  "Sid": "Alarms",
                  "Effect": "Allow",
                  "Action": [
                    "cloudwatch:PutMetricAlarm",
                    "cloudwatch:DeleteAlarms",
                    "cloudwatch:DescribeAlarms"
                  ],
                  "Resource": {
                    "Fn::Sub": "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:norg-edge-*"
                  }
                },
                {
                  "Sid": "Lambda",
                  "Effect": "Allow",
                  "Action": [
                    "lambda:CreateFunction",
                    "lambda:GetFunction",
                    "lambda:GetFunctionConfiguration",
                    "lambda:PublishVersion",
                    "lambda:DeleteFunction",
                    "lambda:UpdateFunctionCode",
                    "lambda:UpdateFunctionConfiguration",
                    "lambda:AddPermission",
                    "lambda:RemovePermission",
                    "lambda:EnableReplication",
                    "lambda:GetPolicy",
                    "lambda:TagResource",
                    "lambda:ListVersionsByFunction"
                  ],
                  "Resource": {
                    "Fn::Sub": "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:norg-edge-*"
                  }
                },
                {
                  "Sid": "LambdaQuotas",
                  "Effect": "Allow",
                  "Action": [
                    "lambda:GetAccountSettings",
                    "servicequotas:GetServiceQuota"
                  ],
                  "Resource": "*"
                },
                {
                  "Sid": "Roles",
                  "Effect": "Allow",
                  "Action": [
                    "iam:CreateRole",
                    "iam:DeleteRole",
                    "iam:GetRole",
                    "iam:PassRole",
                    "iam:PutRolePolicy",
                    "iam:DeleteRolePolicy",
                    "iam:GetRolePolicy",
                    "iam:AttachRolePolicy",
                    "iam:DetachRolePolicy",
                    "iam:TagRole"
                  ],
                  "Resource": {
                    "Fn::Sub": "arn:aws:iam::${AWS::AccountId}:role/norg-edge-*"
                  }
                },
                {
                  "Sid": "ServiceLinkedRoles",
                  "Effect": "Allow",
                  "Action": [
                    "iam:CreateServiceLinkedRole",
                    "iam:GetRole"
                  ],
                  "Resource": [
                    {
                      "Fn::Sub": "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/replicator.lambda.amazonaws.com/AWSServiceRoleForLambdaReplicator"
                    },
                    {
                      "Fn::Sub": "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/logger.cloudfront.amazonaws.com/AWSServiceRoleForCloudFrontLogger"
                    }
                  ]
                },
                {
                  "Sid": "Secrets",
                  "Effect": "Allow",
                  "Action": [
                    "secretsmanager:CreateSecret",
                    "secretsmanager:DeleteResourcePolicy",
                    "secretsmanager:DeleteSecret",
                    "secretsmanager:DescribeSecret",
                    "secretsmanager:GetResourcePolicy",
                    "secretsmanager:GetSecretValue",
                    "secretsmanager:PutResourcePolicy",
                    "secretsmanager:PutSecretValue",
                    "secretsmanager:RemoveRegionsFromReplication",
                    "secretsmanager:ReplicateSecretToRegions",
                    "secretsmanager:TagResource",
                    "secretsmanager:UntagResource",
                    "secretsmanager:UpdateSecret"
                  ],
                  "Resource": {
                    "Fn::Sub": "arn:aws:secretsmanager:us-east-1:${AWS::AccountId}:secret:norg-edge-*"
                  }
                },
                {
                  "Sid": "Schedule",
                  "Effect": "Allow",
                  "Action": [
                    "events:PutRule",
                    "events:DeleteRule",
                    "events:DescribeRule",
                    "events:PutTargets",
                    "events:RemoveTargets"
                  ],
                  "Resource": {
                    "Fn::Sub": "arn:aws:events:us-east-1:${AWS::AccountId}:rule/norg-edge-*"
                  }
                },
                {
                  "Sid": "Logs",
                  "Effect": "Allow",
                  "Action": [
                    "logs:CreateLogGroup",
                    "logs:DeleteLogGroup",
                    "logs:PutRetentionPolicy",
                    "logs:DescribeLogGroups"
                  ],
                  "Resource": "*"
                },
                {
                  "Sid": "ReadRouterLogs",
                  "Effect": "Allow",
                  "Action": [
                    "logs:FilterLogEvents",
                    "logs:GetLogEvents",
                    "logs:DescribeLogStreams"
                  ],
                  "Resource": {
                    "Fn::Sub": "arn:aws:logs:*:${AWS::AccountId}:log-group:/aws/lambda/us-east-1.norg-edge-*"
                  }
                },
                {
                  "Sid": "CloudFrontPolicies",
                  "Effect": "Allow",
                  "Action": [
                    "cloudfront:CreateOriginRequestPolicy",
                    "cloudfront:DeleteOriginRequestPolicy",
                    "cloudfront:CreateCachePolicy",
                    "cloudfront:DeleteCachePolicy",
                    "cloudfront:ListCachePolicies",
                    "cloudfront:ListOriginRequestPolicies"
                  ],
                  "Resource": "*"
                },
                {
                  "Sid": "AccessLogsBucket",
                  "Effect": "Allow",
                  "Action": [
                    "s3:CreateBucket",
                    "s3:DeleteBucket",
                    "s3:GetBucketAcl",
                    "s3:PutBucketAcl",
                    "s3:GetBucketOwnershipControls",
                    "s3:PutBucketOwnershipControls",
                    "s3:PutBucketPublicAccessBlock",
                    "s3:PutLifecycleConfiguration",
                    "s3:ListBucket",
                    "s3:GetObject"
                  ],
                  "Resource": [
                    "arn:aws:s3:::norg-edge-logs-*",
                    "arn:aws:s3:::norg-edge-logs-*/*"
                  ]
                },
                {
                  "Sid": "SelfManagePolicies",
                  "Effect": "Allow",
                  "Action": [
                    "iam:GetUser",
                    "iam:GetUserPolicy",
                    "iam:ListUserPolicies",
                    "iam:ListAttachedUserPolicies",
                    "iam:PutUserPolicy",
                    "iam:DeleteUserPolicy"
                  ],
                  "Resource": {
                    "Fn::Sub": "arn:aws:iam::${AWS::AccountId}:user/${UserName}"
                  }
                }
              ]
            }
          }
        ]
      }
    },
    "InstallerAccessKey": {
      "Type": "AWS::IAM::AccessKey",
      "Properties": {
        "UserName": {
          "Ref": "InstallerUser"
        }
      }
    },
    "InstallerAccessKeySecret": {
      "Type": "AWS::SecretsManager::Secret",
      "Properties": {
        "Name": "norg-edge-installer/access-key",
        "Description": "Access key for NORG's edge installer user. Share both values with NORG through a secure channel, never by email.",
        "SecretString": {
          "Fn::Sub": "{\"access_key_id\": \"${InstallerAccessKey}\", \"secret_access_key\": \"${InstallerAccessKey.SecretAccessKey}\"}"
        }
      }
    }
  },
  "Outputs": {
    "InstallerUserName": {
      "Value": {
        "Ref": "InstallerUser"
      }
    },
    "AccessKeySecretArn": {
      "Value": {
        "Ref": "InstallerAccessKeySecret"
      }
    },
    "NextStep": {
      "Value": "Open Secrets Manager > norg-edge-installer/access-key and share the two values with NORG through a secure channel."
    }
  }
}
