NetApp / terraform-provider-netapp-cloudmanager

Terraform provider to create NetAPP OCCM instances, CVO resources, volumes, snapshots, ... in Azure, AWS, GCP.
Mozilla Public License 2.0
17 stars 27 forks source link

Invalid IAM Instance Profile name for NetApp connector #108

Closed bryanheo closed 2 years ago

bryanheo commented 2 years ago

Hello

We are deploying NetApp connector through Terraform in AWS. We deploy NetApp connector as shown below and when we create NetApp connector, it returns error below. If we re-apply Terraform after the error, it works fine. I assume that there is some dependency issue even though we use depending_on option. Could you investigate the issue?

TF code

resource "aws_iam_instance_profile" "this" {
  count = var.enabled ? 1 : 0
  name  = "connector-instance-profile"
  role  = aws_iam_role.this[0].name
}

resource "aws_iam_role" "this" {
  count = var.enabled ? 1 : 0
  name  = "connector-instance-profile-role"
  path  = "/"

  assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "ec2.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
EOF

  tags = merge(var.common_tags, {
    Name = "connector-instance-profile-role"
  })
}

resource "aws_iam_policy" "this" {
  count       = var.enabled ? 1 : 0
  name        = "connector-instance-policy"
  description = "connector-instance-policy"

  policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "iam:ListInstanceProfiles",
                "iam:CreateRole",
                "iam:DeleteRole",
                "iam:PutRolePolicy",
                "iam:CreateInstanceProfile",
                "iam:DeleteRolePolicy",
                "iam:AddRoleToInstanceProfile",
                "iam:RemoveRoleFromInstanceProfile",
                "iam:DeleteInstanceProfile",
                "ec2:ModifyVolumeAttribute",
                "sts:DecodeAuthorizationMessage",
                "ec2:DescribeImages",
                "ec2:DescribeRouteTables",
                "ec2:DescribeInstances",
                "iam:PassRole",
                "ec2:DescribeInstanceStatus",
                "ec2:RunInstances",
                "ec2:ModifyInstanceAttribute",
                "ec2:CreateTags",
                "ec2:CreateVolume",
                "ec2:DescribeVolumes",
                "ec2:DeleteVolume",
                "ec2:CreateSecurityGroup",
                "ec2:DeleteSecurityGroup",
                "ec2:DescribeSecurityGroups",
                "ec2:RevokeSecurityGroupEgress",
                "ec2:AuthorizeSecurityGroupEgress",
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:RevokeSecurityGroupIngress",
                "ec2:CreateNetworkInterface",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DeleteNetworkInterface",
                "ec2:ModifyNetworkInterfaceAttribute",
                "ec2:DescribeSubnets",
                "ec2:DescribeVpcs",
                "ec2:DescribeDhcpOptions",
                "ec2:CreateSnapshot",
                "ec2:DeleteSnapshot",
                "ec2:DescribeSnapshots",
                "ec2:StopInstances",
                "ec2:GetConsoleOutput",
                "ec2:DescribeKeyPairs",
                "ec2:DescribeRegions",
                "ec2:DeleteTags",
                "ec2:DescribeTags",
                "cloudformation:CreateStack",
                "cloudformation:DeleteStack",
                "cloudformation:DescribeStacks",
                "cloudformation:DescribeStackEvents",
                "cloudformation:ValidateTemplate",
                "cloudformation:ListStacks",
                "cloudwatch:GetMetricStatistics",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:ListAllMyBuckets",
                "s3:GetBucketTagging",
                "s3:GetBucketLocation",
                "s3:CreateBucket",
                "s3:GetBucketPolicyStatus",
                "s3:GetBucketPublicAccessBlock",
                "s3:GetBucketAcl",
                "s3:GetBucketPolicy",
                "kms:List*",
                "kms:Describe*",
                "ec2:AssociateIamInstanceProfile",
                "ec2:DescribeIamInstanceProfileAssociations",
                "ec2:DisassociateIamInstanceProfile",
                "ec2:DescribeInstanceAttribute",
                "ce:GetReservationUtilization",
                "ce:GetDimensionValues",
                "ce:GetCostAndUsage",
                "ce:GetTags",
                "ec2:CreatePlacementGroup",
                "ec2:DeletePlacementGroup",
                "ec2:DescribeVpcEndpoints",
                "ec2:CreateVpcEndpoint",
                "ec2:ModifyVpcEndpoint",
                "ec2:DeleteVpcEndpoints",
                "ec2:DescribeReservedInstancesOfferings",
                "ec2:DescribeInstanceTypeOfferings",
                "tag:getResources",
                "tag:getTagKeys",
                "tag:getTagValues",
                "tag:TagResources",
                "tag:UntagResources",
                "fsx:Describe*",
                "fsx:List*",
                "iam:GetInstanceProfile",
                "eks:ListClusters",
                "eks:DescribeCluster",
                "elasticfilesystem:DescribeFileSystems",
                "athena:StartQueryExecution",
                "athena:GetQueryResults",
                "athena:GetQueryExecution",
                "glue:GetDatabase",
                "glue:GetTable",
                "glue:CreateTable",
                "glue:CreateDatabase",
                "glue:GetPartitions",
                "glue:BatchCreatePartition",
                "glue:BatchDeletePartition",
                "ec2:DescribePlacementGroups",
                "iam:GetRolePolicy",
                "ec2:DescribeVolumesModifications"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:DeleteBucket",
                "s3:GetLifecycleConfiguration",
                "s3:PutLifecycleConfiguration",
                "s3:PutBucketTagging",
                "s3:ListBucketVersions",
                "s3:GetBucketPolicyStatus",
                "s3:GetBucketPublicAccessBlock",
                "s3:GetBucketAcl",
                "s3:GetBucketPolicy",
                "s3:PutBucketPublicAccessBlock"
            ],
            "Resource": "arn:aws:s3:::fabric-pool*",
            "Effect": "Allow",
            "Sid": "fabricPoolPolicy"
        },
        {
            "Action": [
                "s3:DeleteBucket",
                "s3:GetLifecycleConfiguration",
                "s3:PutLifecycleConfiguration",
                "s3:PutBucketTagging",
                "s3:ListBucketVersions",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:ListAllMyBuckets",
                "s3:GetBucketTagging",
                "s3:GetBucketLocation",
                "s3:GetBucketPolicyStatus",
                "s3:GetBucketPublicAccessBlock",
                "s3:GetBucketAcl",
                "s3:GetBucketPolicy",
                "s3:PutBucketPublicAccessBlock",
                "s3:PutEncryptionConfiguration"
            ],
            "Resource": "arn:aws:s3:::netapp-backup-*",
            "Effect": "Allow",
            "Sid": "backupPolicy"
        },
        {
            "Condition": {
                "StringLike": {
                    "ec2:ResourceTag/netapp-adc-manager": "*"
                }
            },
            "Action": [
                "ec2:StartInstances",
                "ec2:TerminateInstances"
            ],
            "Resource": "arn:aws:ec2:*:*:instance/*",
            "Effect": "Allow"
        },
        {
            "Condition": {
                "StringLike": {
                    "ec2:ResourceTag/GFCInstance": "*"
                }
            },
            "Action": [
                "ec2:StartInstances",
                "ec2:TerminateInstances",
                "ec2:AttachVolume",
                "ec2:DetachVolume"
            ],
            "Resource": "arn:aws:ec2:*:*:instance/*",
            "Effect": "Allow"
        },
        {
            "Condition": {
                "StringLike": {
                    "ec2:ResourceTag/WorkingEnvironment": "*"
                }
            },
            "Action": [
                "ec2:StartInstances",
                "ec2:TerminateInstances",
                "ec2:AttachVolume",
                "ec2:DetachVolume"
            ],
            "Resource": "arn:aws:ec2:*:*:instance/*",
            "Effect": "Allow"
        },
        {
            "Condition": {
                "StringLike": {
                    "ec2:ResourceTag/WorkingEnvironment": "*"
                }
            },
            "Action": [
                "ec2:ModifyVolume"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:volume/*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "ec2:AttachVolume",
                "ec2:DetachVolume"
            ],
            "Resource": "arn:aws:ec2:*:*:volume/*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:DeleteObject",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::netapp-backup-*"
            ],
            "Effect": "Allow"
        }
    ]
}
EOF

  tags = merge(var.common_tags, {
    Name = "connector-instance-policy"
  })
}

resource "aws_iam_role_policy_attachment" "this" {
  count      = var.enabled ? 1 : 0
  role       = aws_iam_role.this[0].name
  policy_arn = aws_iam_policy.this[0].arn
}

resource "netapp-cloudmanager_connector_aws" "this" {
  count                       = var.enabled ? 1 : 0
  name                        = "netapp-${var.account}-connector"
  region                      = var.region
  key_name                    = var.key_pair_name
  company                     = var.company
  instance_type               = var.instance_type
  subnet_id                   = data.aws_subnet.this.id
  security_group_id           = aws_security_group.this[0].id
  iam_instance_profile_name   = aws_iam_instance_profile.this[0].name
  account_id                  = var.netapp_account_id
  associate_public_ip_address = false

  depends_on = [
    aws_security_group.this,
    aws_iam_instance_profile.this
  ]
}

Error

 Error: InvalidParameterValue: Value (connector-instance-profile) for parameter iamInstanceProfile.name is invalid. Invalid IAM Instance Profile name
│       status code: 400, request id: c94c6b81-168e-445b-88a4-21cfd65e8197
│ 
│   with module.use1.module.connector.netapp-cloudmanager_connector_aws.this[0],
│   on ../../../tf-module-aws-netapp/modules/connector/connector.tf line 1, in resource "netapp-cloudmanager_connector_aws" "this":
│    1: resource "netapp-cloudmanager_connector_aws" "this" {

Regards, Moon

bryanheo commented 2 years ago

Do you have any updates about the issue above?

bryanheo commented 2 years ago

I have just noticed that I am not the only one facing the issue. It seems that this issue is related to terraform-provider-aws rather than netapp-cloudmanager_connector_aws https://github.com/terraform-providers/terraform-provider-aws/issues/838

I have tried 'sleep 40' local command and it works ok. For the reason, I assume that instance profile is created slower than netapp-cloudmanager_connector_aws.

resource "aws_iam_instance_profile" "this" {
  count = var.enabled ? 1 : 0
  name  = "connector-instance-profile"
  role  = aws_iam_role.this[0].name

  provisioner "local-exec" {
      command = "sleep 40" # wait for instance profile to appear due to 
  }
}
lonico commented 2 years ago

Yes, this was my hunch that it was an external issue. It seems the AWS provider is indicating completion before the resource is available. We saw similar issues in the past with some API calls as well.

Adding a sleep is a good strategy. We'll document this.

I wonder if there is a way in Terraform to confirm a resource is available beyond depends_on.