hashicorp / terraform-provider-aws

The AWS Provider enables Terraform to manage AWS resources.
https://registry.terraform.io/providers/hashicorp/aws
Mozilla Public License 2.0
9.86k stars 9.2k forks source link

[Bug]: unable to revoke Lake Formation Permissions: InvalidInputException: No permissions revoked. Revoking Tag permissions on Tags that grantee does not have permissions on #35160

Closed gss2002 closed 10 months ago

gss2002 commented 10 months ago

Terraform Core Version

1.6.2

AWS Provider Version

5.31.0

Affected Resource(s)

aws_lakeformation_permissions w/ lf_tag

Expected Behavior

No Changes to Apply or ability to destroy the terraform workspace

Actual Behavior

The plan decides that the resource needs to be replaced. Looking at the PLAN, Terraform is seeing false current values for both sets of permissions.

With 'permissions' it is removing and re-adding the 'ASSOCIATE' , which has not changed in the TF code at all and with 'permissions_with_grant_option' it is removing options that are not even defined in the TF code or in AWS

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

#aws_lakeformation_permissions.re_role_glue_tv_cleanup_perms["arn:aws:iam::1234567890:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_ReliabilityEngineer_720179e260205ced"] must be replaced
-/+ resource "aws_lakeformation_permissions" "re_role_glue_tv_cleanup_perms" {
      ~ id                            = "257793025" -> (known after apply)
      ~ permissions                   = [ # forces replacement
          - "ASSOCIATE",
            "DESCRIBE",
          + "ASSOCIATE",
        ]

With 'permissions_with_grant_option' it is trying to remove permissions that never existed

      ~ permissions_with_grant_option = [
          - "ALTER",
          - "ASSOCIATE",
          - "DESCRIBE",
          - "DROP",
        ] -> (known after apply)
        # (2 unchanged attributes hidden)

      ~ lf_tag {
          ~ catalog_id = "1234567890" -> (known after apply)
          ~ values     = [ # forces replacement
              - "*",
              + "false",
              + "true",
            ]
            # (1 unchanged attribute hidden)
        }
    }

Relevant Error/Panic Output Snippet

Terraform v1.6.2
on linux_amd64
Initializing plugins and modules...
aws_lakeformation_permissions.re_role_glue_tv_cleanup_perms["arn:aws:iam::1234567890:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_ReliabilityEngineer_720179e260205ced"]: Destroying... [id=257793025]
╷
│ Error: unable to revoke LakeFormation Permissions (input: {
│   Permissions: ["ASSOCIATE","DESCRIBE"],
│   PermissionsWithGrantOption: [
│     "ALTER",
│     "ASSOCIATE",
│     "DESCRIBE",
│     "DROP"
│   ],
│   Principal: {
│     DataLakePrincipalIdentifier: "arn:aws:iam::1234567890:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_ReliabilityEngineer_720179e260205ced"
│   },
│   Resource: {
│     LFTag: {
│       CatalogId: "1234567890",
│       TagKey: "glue-version-cleanup",
│       TagValues: ["*"]
│     }
│   }
│ }): unable to revoke Lake Formation Permissions: InvalidInputException: No permissions revoked. Revoking Tag permissions on Tags that grantee does not have permissions on.
│ 
│

Terraform Configuration Files

main.tf

resource "aws_lakeformation_lf_tag" "glue_version_cleanup" {
  key    = "glue-version-cleanup"
  values = ["true", "false"]
}

resource "aws_lakeformation_permissions" "re_role_glue_tv_cleanup_perms" {
  ##depends_on = [aws_lakeformation_lf_tag.glue_version_cleanup]
  for_each = data.aws_iam_roles.lakeformation_sso_admin_role.arns
  principal   = each.value
  permissions = ["DESCRIBE", "ASSOCIATE"]
  lf_tag {
    key    = "glue-version-cleanup"
    values = ["true", "false"]
  }
}

resource "aws_lakeformation_permissions" "glue_version_cleanup_table" {
  principal                     = data.aws_iam_role.edm_glue_tvcleanup_lambda_role.arn
  permissions                   = ["DESCRIBE"]

  lf_tag_policy {
    resource_type = "TABLE"

    expression {
      key    = aws_lakeformation_lf_tag.glue_version_cleanup.key
      values = ["true"]
    }
  }

}

resource "aws_lakeformation_permissions" "glue_version_cleanup_db" {
  principal                     = data.aws_iam_role.edm_glue_tvcleanup_lambda_role.arn
  permissions                   = ["DESCRIBE"]

  lf_tag_policy {
    resource_type = "DATABASE"

    expression {
      key    = aws_lakeformation_lf_tag.glue_version_cleanup.key
      values = ["true"]
    }
  }

}

provider.tf

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.31.0"
    }
  }
}
provider "aws" {
  region  = var.region
  assume_role {
    role_arn    = var.role_arn
    external_id = var.external_id
  }
}

data.tf

data "aws_iam_roles" "lakeformation_sso_admin_role" {
  name_regex  = var.lakeformation_sso_admin_regex
  path_prefix = "/aws-reserved/sso.amazonaws.com/"
}
data "aws_iam_role" "edm_glue_tvcleanup_lambda_role" {
  name = "${var.lob}-${var.env}-glue-tvcleanup-lambda-role"
}

variables.tf

# provider specific variables:
variable "region" {
  type        = string
  description = "The full name of the region to select"
  default     = "us-east-1"
}
variable "role_arn" {
  type        = string
  description = "Role ARN"
}
variable "external_id" {
  type        = string
  description = "Authentication key"
}

variable "lob" {
  type        = string
  description = "Line of business"
  default     = "datalake"
}
variable "env" {
  type        = string
  description = "Environment"
  default     = "dev"
}

variable "create" {
  type        = bool
  default     = true
  description = "Set to false to skip creation"
}

variable "use_prefix" {
  type        = bool
  default     = false
  description = "Set to true to create using bucket prefix"
}

variable "block_public_access" {
  type        = bool
  default     = true
  description = "Block public access to the bucket - all 4 settings are blocked"
}

variable "glue-catalogdb-name" {
  type        = string
  default     = "sample_db"
  description = "Name of the glue catalog database"
}

variable "glue-table-name" {
  type        = string
  default     = "sample_table"
  description = "Name of the glue table"
}

variable "lakeformation_role" {
  type        = string
  default     = "administrator"
  description = "Role of the Lakeformation"
}

variable "lakeformation_sso_admin_regex" {
  type        = string
  default     = "AWSReservedSSO_ReliabilityEngineer_*"
  description = "Regex pattern for SSO role to define as Lake Formation Admin"
}

Steps to Reproduce

terraform plan
terraform apply

or

terraform plan -destroy
terraform apply -destroy

Debug Output

No response

Panic Output

No response

Important Factoids

Using Terraform Enterprise

References

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lakeformation_permissions

Would you like to implement a fix?

None

github-actions[bot] commented 10 months ago

Community Note

Voting for Prioritization

Volunteering to Work on This Issue

justinretzolk commented 10 months ago

Related #34003 Related #31096 Related #22570

gss2002 commented 10 months ago

@justinretzolk - This sums it up best right here basically

If the principal is also a data lake administrator, AWS grants implicit permissions that can cause errors using this resource. For example, AWS implicitly grants a principal/administrator permissions and permissions_with_grant_option of ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, and SELECT on a table. If you use this resource to explicitly grant the principal/administrator permissions but not permissions_with_grant_option of ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, and SELECT on the table, this resource will read the implicit permissions_with_grant_option and attempt to revoke them when the resource is destroyed. Doing so will cause an InvalidInputException: No permissions revoked error because you cannot revoke implicit permissions per se. To workaround this problem, explicitly grant the principal/administrator permissions and permissions_with_grant_option, which can then be revoked. Similarly, granting a principal/administrator permissions on a table with columns and providing column_names, will result in a InvalidInputException: Permissions modification is invalid error because you are narrowing the implicit permissions. Instead, set wildcard to true and remove the column_names.

Thank you!

github-actions[bot] commented 9 months ago

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.