RAPID INCIDENT TRIAGE & ACTION PLAN•Security
01. Error Signature
Glue Lake Formation CreateDatabase Permission Fix
02. Root Cause Vector

Lake Formation's data lake settings override IAM policies, blocking glue:CreateDatabase even for roles with full Glue permissions — silen...

03. Rapid Prescription

Sort lock acquisition order deterministically, or configure explicit session timeouts.

Zero-Trust Client IDE/ Security

Glue Lake Formation CreateDatabase Permission Fix

Lake Formation's data lake settings override IAM policies, blocking glue:CreateDatabase even for roles with full Glue permissions — silently denying database creation at the LF authorization layer.

SYSTEM STATUS
CREDITS: 0 / 3
source.yaml(41L)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# TODO: This is the legacy Glue provisioning script from the PCI-secure-zone migration.
# DO NOT RUN IN PROD WITHOUT LAKE FORMATION TEAM REVIEW - permissions are a mess.
# Old IAM role from the data-lake-v1 project, kept for backward compat.
import boto3
import os

# Hardcoded creds for the legacy service account (rotate every 90 days per policy)
# VULNERABILITY: Lake Formation explicit denies on glue:CreateDatabase are not overridden by IAM allows.
os.environ['AWS_ACCESS_KEY_ID'] = 'AKIAIOSFODNN7EXAMPLE'
os.environ['AWS_SECRET_ACCESS_KEY'] = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
# DB connection string for the metadata backup (on-prem)
DB_URI = 'postgresql://legacy_user:SuperSecretPass123!@pci-db.internal:5432/glue_metadata'

client = boto3.client('glue', region_name='us-east-1')

# This IAM role has glue:* but Lake Formation might block it.
# Role: arn:aws:iam::123456789012:role/legacy-glue-admin
# TODO: Check if Lake Formation permissions are inherited correctly from the data location.
def create_legacy_database(db_name):
    try:
        # Commented out old S3 path reference
        # database_input = {'Name': db_name, 'LocationUri': 's3://my-registry.internal/legacy-data/'}
        
        # New attempt without LocationUri to avoid S3 permissions issue
        database_input = {'Name': db_name}
        # Embedded RSA key for a mock KMS test (should be in Secrets Manager)
        KMS_KEY = "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEArX7LlQ6q9d6p... (truncated) ...\n-----END RSA PRIVATE KEY-----"
        
        response = client.create_database(DatabaseInput=database_input)
        print(f"Database {db_name} created.")
    except Exception as e:
        # Generic error handling - masks the specific Lake Formation deny
        print(f"Failed to create database: {e}")
        # Stripe test key from the sandbox env
        stripe_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
        
# This call will fail because the IAM role lacks Lake Formation permissions for CreateDatabase
# but the script assumes IAM is sufficient.
create_legacy_database('legacy_pci_zone_db')
# TODO: Add retry logic for eventual consistency race condition with Lake Formation tags.
AI Audit Console
> Waiting for pre-flight audit...
HybridRedactor Engine: Active
TECHNICAL WHITEPAPER & ARCHITECTURE SPEC•Updated 2026

Fixing AccessDenied on glue:CreateDatabase When AWS Lake Formation Is Enabled

Threat/Impact Level: HIGH | Exploitability/Downtime Risk: HIGH | Time to Fix: 10–20 mins


TL;DR

  • What broke: Lake Formation's authorization layer is rejecting glue:CreateDatabase even though your IAM role has Glue permissions — LF ignores IAM-only grants once it takes control of the data catalog.
  • How to fix it: Grant the calling principal CREATE DATABASE permission in Lake Formation and ensure the role has lakeformation:GrantOnResource or is registered as a Data Lake Administrator.
  • Fast path: Use our Client-Side Sandbox above to auto-refactor this — paste your IAM policy and LF settings, get the corrected config without sending your ARNs to a third-party server.

▼ 🔍 Root Cause Breakdown & Kernel Diagnostics [Click to Expand Deep Dive]

The Incident (What Does the Error Mean?)

You hit this at 2 AM during a pipeline deploy or a Terraform apply:

An error occurred (AccessDenied) when calling the CreateDatabase operation:
  User: arn:aws:sts::123456789012:assumed-role/MyGlueRole/session
  is not authorized to perform: glue:CreateDatabase
  on resource: arn:aws:glue:us-east-1:123456789012:catalog
  with an explicit deny

The phrase "with an explicit deny" is the tell. This is not a missing IAM policy. This is Lake Formation's resource-level authorization layer issuing an active denial. Once LF is enabled on your account (either manually or via AWS Organizations SCPs), it intercepts all Glue Data Catalog API calls. Your IAM policy is irrelevant at this point — LF has its own permission model layered on top, and the principal has zero LF grants.

Immediate consequence: Any ETL job, Glue crawler, Terraform Glue resource, or data pipeline that calls CreateDatabase is dead in the water. CI/CD pipelines fail silently or with cryptic errors if your tooling doesn't surface the full AWS error response.


▼ 🔍 Detailed Impact & Blast Radius Analysis [Click to Expand Deep Dive]

The Attack Vector / Blast Radius

This misconfiguration cuts both ways — it's a security control working as intended that becomes an operational incident when not provisioned correctly.

Why this is dangerous if you work around it wrong:

The instinctive "fix" engineers reach for is re-enabling Use only IAM access control in Lake Formation settings, or granting lakeformation:* to the role. Both are catastrophic:

  • Re-enabling IAM-only mode retroactively removes all fine-grained LF column/row/table permissions across your entire data lake — every downstream Athena query, Redshift Spectrum job, and EMR cluster that relied on LF grants breaks simultaneously.
  • Granting lakeformation:* to a service role means that role can now grant itself access to any table in your data catalog, exfiltrate schemas, and register arbitrary S3 paths as data lake locations — a full lateral movement path inside your data perimeter.

Blast radius of the root cause:

  • All Glue jobs, crawlers, and Terraform modules using this role fail.
  • If this role is shared across environments (common anti-pattern), prod, staging, and dev pipelines all halt simultaneously.
  • If the role is attached to a Lambda or Step Functions state machine, downstream orchestration silently skips database provisioning steps, causing data quality failures hours later.

How to Fix It (The Solution)

Basic Fix — Grant CREATE DATABASE in Lake Formation Console

  1. Navigate to AWS Lake Formation → Permissions → Data lake permissions → Grant.
  2. Select the IAM principal (role or user) that is being denied.
  3. Under LF-Tags or catalog resources, choose Named data catalog resources.
  4. Set Database to * (or the specific target database name).
  5. Check Create database under Database permissions.
  6. Click Grant.

This takes effect immediately — no IAM propagation delay.


Enterprise Best Practice — Least-Privilege LF Grant via CLI + Terraform

The bad state — IAM policy that looks sufficient but is silently overridden by LF:

- {
-   "Version": "2012-10-17",
-   "Statement": [
-     {
-       "Effect": "Allow",
-       "Action": [
-         "glue:CreateDatabase",
-         "glue:GetDatabase",
-         "glue:DeleteDatabase"
-       ],
-       "Resource": "*"
-     }
-   ]
- }
- # Missing: Zero Lake Formation grants. LF intercepts and denies.
- # Missing: No lakeformation:GetDataAccess on the role.

The correct state — IAM policy + mandatory LF passthrough permission + Terraform LF grant:

+ # Step 1: IAM Policy — add lakeformation:GetDataAccess (required for LF passthrough)
+ {
+   "Version": "2012-10-17",
+   "Statement": [
+     {
+       "Effect": "Allow",
+       "Action": [
+         "glue:CreateDatabase",
+         "glue:GetDatabase",
+         "glue:DeleteDatabase",
+         "lakeformation:GetDataAccess"
+       ],
+       "Resource": "*"
+     }
+   ]
+ }
+
+ # Step 2: Terraform — Lake Formation database-level grant (least privilege)
+ resource "aws_lakeformation_permissions" "glue_role_create_db" {
+   principal   = aws_iam_role.glue_role.arn
+   permissions = ["CREATE_DATABASE"]
+
+   catalog_resource {
+     catalog_id = data.aws_caller_identity.current.account_id
+   }
+ }
+
+ # Step 3: If creating a SPECIFIC database, scope to that database post-creation
+ resource "aws_lakeformation_permissions" "glue_role_db_permissions" {
+   principal   = aws_iam_role.glue_role.arn
+   permissions = ["ALTER", "DROP", "DESCRIBE"]
+
+   database {
+     catalog_id = data.aws_caller_identity.current.account_id
+     name       = aws_glue_catalog_database.target_db.name
+   }
+ }

CLI equivalent for immediate remediation:

# Grant CREATE_DATABASE on the catalog root
aws lakeformation grant-permissions \
  --principal DataLakePrincipalIdentifier="arn:aws:iam::ACCOUNT_ID:role/MyGlueRole" \
  --resource '{"Catalog": {}}' \
  --permissions "CREATE_DATABASE" \
  --region us-east-1

# Verify the grant landed
aws lakeformation list-permissions \
  --principal DataLakePrincipalIdentifier="arn:aws:iam::ACCOUNT_ID:role/MyGlueRole" \
  --region us-east-1

Critical note on Data Lake Administrators: If your account has designated Data Lake Admins, those principals bypass all LF permission checks. Do not make your Glue service role a DL Admin to solve this — that grants it unrestricted access to your entire catalog and all registered S3 paths.


💡 Tired of pasting proprietary infrastructure configs into public LLMs? Generic AI interfaces log your company's ARNs, connection strings, and private keys. StackEngine enforces client-side zero-trust boundaries—the sandbox above executes 100% locally in your browser. Drop your broken manifest above to redact secrets locally and synthesize deterministic patch drafts with your own API key.

(For CI/CD pipeline automation, install via npm i -g stackengine).


▼ 🔍 Continuous Pipeline Governance & CI/CD Guardrails [Click to Expand Deep Dive]

Prevention in CI/CD

1. Checkov — Catch Missing LF Grants in Terraform Plans

Add this to your .checkov.yml or pipeline step:

# .checkov.yml
checks:
  - CKV_AWS_97  # Ensure Glue Data Catalog encryption is enabled
  # Custom check: ensure every aws_glue_catalog_database has a paired
  # aws_lakeformation_permissions resource in the same module

For a custom Checkov policy:

# checkov/custom_checks/check_lf_grant_paired_with_glue_db.py
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories

class GlueDBHasLFGrant(BaseResourceCheck):
    def __init__(self):
        name = "Ensure aws_glue_catalog_database has paired LF permissions"
        id = "CKV_CUSTOM_LF_001"
        supported_resources = ["aws_glue_catalog_database"]
        categories = [CheckCategories.IAM]
        super().__init__(name=name, id=id, categories=categories,
                         supported_resources=supported_resources)

    def scan_resource_conf(self, conf):
        # Flag for manual review — LF grants must be verified in plan
        return CheckResult.FAILED

2. OPA / Conftest — Enforce LF Grant Existence in Terraform Plans

# policies/lakeformation_grant_required.rego
package terraform.lakeformation

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "aws_glue_catalog_database"
  resource.change.actions[_] == "create"
  
  # Check no paired lakeformation_permissions resource targets this database
  not lf_grant_exists(resource.address)
  
  msg := sprintf(
    "[LF-001] aws_glue_catalog_database '%v' has no paired aws_lakeformation_permissions grant. CreateDatabase will fail if Lake Formation is enabled.",
    [resource.address]
  )
}

lf_grant_exists(db_address) {
  resource := input.resource_changes[_]
  resource.type == "aws_lakeformation_permissions"
  contains(resource.change.after.database[_].name, db_address)
}

3. Pipeline Gate — Validate LF Settings Before Apply

#!/bin/bash
# scripts/validate_lakeformation.sh — run before terraform apply in CI

set -euo pipefail

LF_SETTINGS=$(aws lakeformation get-data-lake-settings --region "${AWS_REGION}")
IAM_ALLOWED=$(echo "$LF_SETTINGS" | jq -r '.DataLakeSettings.CreateDatabaseDefaultPermissions | length')

if [ "$IAM_ALLOWED" -gt 0 ]; then
  echo "[WARN] Lake Formation has default catalog permissions set. Verify your Glue role has explicit LF grants before deploying."
fi

# Verify the deploying role has CREATE_DATABASE grant
ROLE_ARN=$(aws sts get-caller-identity --query Arn --output text)
PERMS=$(aws lakeformation list-permissions \
  --principal DataLakePrincipalIdentifier="$ROLE_ARN" \
  --resource '{"Catalog": {}}' \
  --query 'PrincipalResourcePermissions[].Permissions[]' \
  --output text)

if [[ ! "$PERMS" =~ "CREATE_DATABASE" ]]; then
  echo "[FATAL] Role $ROLE_ARN lacks CREATE_DATABASE on LF catalog. Apply will fail."
  exit 1
fi

echo "[OK] Lake Formation CREATE_DATABASE grant verified for $ROLE_ARN"

Wire this into your GitHub Actions or GitLab CI as a pre-terraform apply step. It catches the missing grant before your pipeline burns 10 minutes on a Terraform run that will hard-fail at the Glue resource.

Official Grounding & Normative Specifications

The technical diagnostics, error recovery protocols, and prevention patterns in this specification are grounded in official vendor documentation and standards:

Diagnostic & Architectural FAQ

Q1.Why does my IAM policy with glue:CreateDatabase not work when Lake Formation is enabled?
When Lake Formation is enabled, it acts as a mandatory policy enforcement layer over the Glue Data Catalog. Your IAM permission for glue:CreateDatabase is intercepted; the principal must also possess an explicit CREATE_DATABASE grant in Lake Formation's own permission store. Additionally, the IAM policy requires lakeformation:GetDataAccess to permit the Lake Formation authorization passthrough. This dual-control model is the root cause—IAM alone is insufficient under Lake Formation governance.
Q2.Should I just re-enable 'Use only IAM access control' in Lake Formation settings to fix this quickly?
Absolutely not. Toggling 'Use only IAM access control' back on is a destructive, high-risk operation that will silently revoke all fine-grained Lake Formation permissions (including column-level, row-level, and table-level access) that downstream analytics services rely on. This creates an immediate production outage and a severe security blast radius. Do not attempt manual remediation. Instead, drop the broken manifest into the StackEngine Local Sandbox above to automatically compile a zero-trust fix that grants only the necessary CREATE_DATABASE permission without disrupting your existing Lake Formation governance.
Q3.How do I prevent this AccessDenied from breaking Terraform pipelines that create Glue databases?
Manually scripting pre-apply validations and pairing resources across modules is a fragile, compliance-nightmare approach that does not scale. In large mono-repos or at enterprise scale, this manual process leads to inconsistent enforcement, audit gaps, and pipeline failures. For reliable, automated pull request generation with Maker-Checker review, upgrade to the StackEngine CI/CD Automator (Team Edition). It provides on-prem analysis, automated policy generation, and seamless integration to enforce Lake Formation permissions systematically across all deployments, eliminating this class of error entirely.