Skip to content

Commit a0e647d

Browse files
committed
X
1 parent c5c5df7 commit a0e647d

File tree

3 files changed

+316
-0
lines changed

3 files changed

+316
-0
lines changed

apply_iam_inline_policy.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Apply IAM inline policy to daylily-service user for zebra_day DynamoDB access.
4+
Uses inline policy to avoid the 10 managed policies per user limit.
5+
"""
6+
import json
7+
import sys
8+
import time
9+
10+
try:
11+
import boto3
12+
from botocore.exceptions import ClientError
13+
except ImportError:
14+
print("ERROR: boto3 is not installed. Install with: pip install boto3")
15+
sys.exit(1)
16+
17+
POLICY_FILE = "iam-policy-daylily-service-zebra-day.json"
18+
POLICY_NAME = "ZebraDayDynamoDBAccess"
19+
USER_NAME = "daylily-service"
20+
21+
22+
def main():
23+
# Get AWS profile from command line or environment
24+
profile = sys.argv[1] if len(sys.argv) > 1 else None
25+
26+
# Load policy document
27+
try:
28+
with open(POLICY_FILE, "r") as f:
29+
policy_document = json.load(f)
30+
except FileNotFoundError:
31+
print(f"ERROR: Policy file '{POLICY_FILE}' not found")
32+
sys.exit(1)
33+
except json.JSONDecodeError as e:
34+
print(f"ERROR: Invalid JSON in policy file: {e}")
35+
sys.exit(1)
36+
37+
# Create IAM client
38+
session_kwargs = {}
39+
if profile:
40+
session_kwargs["profile_name"] = profile
41+
print(f"Using AWS profile: {profile}")
42+
43+
session = boto3.Session(**session_kwargs)
44+
iam = session.client("iam")
45+
46+
# Put inline policy (creates or updates)
47+
print(f"Adding inline policy '{POLICY_NAME}' to user '{USER_NAME}'...")
48+
try:
49+
iam.put_user_policy(
50+
UserName=USER_NAME,
51+
PolicyName=POLICY_NAME,
52+
PolicyDocument=json.dumps(policy_document),
53+
)
54+
print(f"✓ Inline policy '{POLICY_NAME}' added to user '{USER_NAME}'")
55+
except ClientError as e:
56+
if e.response["Error"]["Code"] == "NoSuchEntity":
57+
print(f"ERROR: User '{USER_NAME}' does not exist")
58+
sys.exit(1)
59+
else:
60+
print(f"ERROR adding inline policy: {e}")
61+
sys.exit(1)
62+
63+
# Verify inline policy
64+
print(f"\nVerifying inline policy...")
65+
try:
66+
response = iam.list_user_policies(UserName=USER_NAME)
67+
inline_policies = response.get("PolicyNames", [])
68+
69+
if POLICY_NAME in inline_policies:
70+
print(f"✓ Inline policy '{POLICY_NAME}' is attached to '{USER_NAME}'")
71+
else:
72+
print(f"⚠ WARNING: Policy not found in inline policies list")
73+
74+
print(f"\nAll inline policies for '{USER_NAME}':")
75+
for policy_name in inline_policies:
76+
print(f" - {policy_name}")
77+
except ClientError as e:
78+
print(f"ERROR verifying inline policy: {e}")
79+
sys.exit(1)
80+
81+
# Wait for IAM propagation
82+
print(f"\n⏳ Waiting 60 seconds for IAM policy propagation...")
83+
time.sleep(60)
84+
print("✓ Wait complete")
85+
86+
# Test DynamoDB access with daylily-service-lsmc profile
87+
print(f"\nTesting DynamoDB access to 'zebra-day-config' in us-west-2...")
88+
print(f"(Using profile: daylily-service-lsmc)")
89+
try:
90+
test_session = boto3.Session(profile_name="daylily-service-lsmc")
91+
dynamodb = test_session.client("dynamodb", region_name="us-west-2")
92+
response = dynamodb.describe_table(TableName="zebra-day-config")
93+
print(f"✓ Successfully accessed table 'zebra-day-config'")
94+
print(f" Status: {response['Table']['TableStatus']}")
95+
print(f" Items: {response['Table']['ItemCount']}")
96+
except ClientError as e:
97+
if e.response["Error"]["Code"] == "AccessDeniedException":
98+
print(f"⚠ WARNING: Still getting AccessDeniedException")
99+
print(f" This may indicate:")
100+
print(f" 1. IAM propagation needs more time (wait another 30-60s)")
101+
print(f" 2. AWS credentials are not using the 'daylily-service' user")
102+
print(f" 3. Additional permissions are needed")
103+
elif e.response["Error"]["Code"] == "ResourceNotFoundException":
104+
print(f"⚠ WARNING: Table 'zebra-day-config' does not exist in us-west-2")
105+
print(f" Run: zday dynamo init --region us-west-2")
106+
else:
107+
print(f"ERROR testing DynamoDB access: {e}")
108+
except Exception as e:
109+
print(f"ERROR: {e}")
110+
111+
print(f"\n{'='*60}")
112+
print(f"IAM inline policy setup complete!")
113+
print(f"{'='*60}")
114+
print(f"\nNext steps:")
115+
print(f"1. Test the GUI backend switch at https://localhost:8118/config")
116+
print(f"2. If still getting errors, wait another 30-60 seconds for IAM propagation")
117+
print(f"3. Use AWS profile: daylily-service-lsmc")
118+
119+
120+
if __name__ == "__main__":
121+
main()
122+

apply_iam_policy.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Apply IAM policy to daylily-service user for zebra_day DynamoDB access.
4+
"""
5+
import json
6+
import sys
7+
import time
8+
9+
try:
10+
import boto3
11+
from botocore.exceptions import ClientError
12+
except ImportError:
13+
print("ERROR: boto3 is not installed. Install with: pip install boto3")
14+
sys.exit(1)
15+
16+
POLICY_FILE = "iam-policy-daylily-service-zebra-day.json"
17+
POLICY_NAME = "ZebraDayDynamoDBAccess"
18+
USER_NAME = "daylily-service"
19+
ACCOUNT_ID = "108782052779"
20+
21+
22+
def main():
23+
# Get AWS profile from command line or environment
24+
profile = sys.argv[1] if len(sys.argv) > 1 else None
25+
26+
# Load policy document
27+
try:
28+
with open(POLICY_FILE, "r") as f:
29+
policy_document = json.load(f)
30+
except FileNotFoundError:
31+
print(f"ERROR: Policy file '{POLICY_FILE}' not found")
32+
sys.exit(1)
33+
except json.JSONDecodeError as e:
34+
print(f"ERROR: Invalid JSON in policy file: {e}")
35+
sys.exit(1)
36+
37+
# Create IAM client
38+
session_kwargs = {}
39+
if profile:
40+
session_kwargs["profile_name"] = profile
41+
print(f"Using AWS profile: {profile}")
42+
43+
session = boto3.Session(**session_kwargs)
44+
iam = session.client("iam")
45+
46+
# Step 1: Create the policy
47+
print(f"Creating IAM policy '{POLICY_NAME}'...")
48+
policy_arn = f"arn:aws:iam::{ACCOUNT_ID}:policy/{POLICY_NAME}"
49+
50+
try:
51+
response = iam.create_policy(
52+
PolicyName=POLICY_NAME,
53+
PolicyDocument=json.dumps(policy_document),
54+
Description="Grants zebra_day access to DynamoDB table and S3 backup buckets",
55+
)
56+
print(f"✓ Policy created: {response['Policy']['Arn']}")
57+
policy_arn = response["Policy"]["Arn"]
58+
except ClientError as e:
59+
if e.response["Error"]["Code"] == "EntityAlreadyExists":
60+
print(f"⚠ Policy '{POLICY_NAME}' already exists, using existing policy")
61+
print(f" ARN: {policy_arn}")
62+
else:
63+
print(f"ERROR creating policy: {e}")
64+
sys.exit(1)
65+
66+
# Step 2: Attach policy to user
67+
print(f"\nAttaching policy to user '{USER_NAME}'...")
68+
try:
69+
iam.attach_user_policy(
70+
UserName=USER_NAME,
71+
PolicyArn=policy_arn,
72+
)
73+
print(f"✓ Policy attached to user '{USER_NAME}'")
74+
except ClientError as e:
75+
if e.response["Error"]["Code"] == "NoSuchEntity":
76+
print(f"ERROR: User '{USER_NAME}' does not exist")
77+
sys.exit(1)
78+
else:
79+
print(f"ERROR attaching policy: {e}")
80+
sys.exit(1)
81+
82+
# Step 3: Verify attachment
83+
print(f"\nVerifying policy attachment...")
84+
try:
85+
response = iam.list_attached_user_policies(UserName=USER_NAME)
86+
attached_policies = response.get("AttachedPolicies", [])
87+
88+
found = False
89+
for policy in attached_policies:
90+
if policy["PolicyName"] == POLICY_NAME:
91+
found = True
92+
print(f"✓ Policy '{POLICY_NAME}' is attached to '{USER_NAME}'")
93+
break
94+
95+
if not found:
96+
print(f"⚠ WARNING: Policy not found in attached policies list")
97+
98+
print(f"\nAll attached policies for '{USER_NAME}':")
99+
for policy in attached_policies:
100+
print(f" - {policy['PolicyName']} ({policy['PolicyArn']})")
101+
except ClientError as e:
102+
print(f"ERROR verifying attachment: {e}")
103+
sys.exit(1)
104+
105+
# Step 4: Wait for IAM propagation
106+
print(f"\n⏳ Waiting 60 seconds for IAM policy propagation...")
107+
time.sleep(60)
108+
print("✓ Wait complete")
109+
110+
# Step 5: Test DynamoDB access
111+
print(f"\nTesting DynamoDB access to 'zebra-day-config' in us-west-2...")
112+
try:
113+
dynamodb = session.client("dynamodb", region_name="us-west-2")
114+
response = dynamodb.describe_table(TableName="zebra-day-config")
115+
print(f"✓ Successfully accessed table 'zebra-day-config'")
116+
print(f" Status: {response['Table']['TableStatus']}")
117+
print(f" Items: {response['Table']['ItemCount']}")
118+
except ClientError as e:
119+
if e.response["Error"]["Code"] == "AccessDeniedException":
120+
print(f"⚠ WARNING: Still getting AccessDeniedException")
121+
print(f" This may indicate:")
122+
print(f" 1. IAM propagation needs more time (wait another 30-60s)")
123+
print(f" 2. AWS credentials are not using the 'daylily-service' user")
124+
print(f" 3. Additional permissions are needed")
125+
elif e.response["Error"]["Code"] == "ResourceNotFoundException":
126+
print(f"⚠ WARNING: Table 'zebra-day-config' does not exist in us-west-2")
127+
print(f" Run: zday dynamo init --region us-west-2")
128+
else:
129+
print(f"ERROR testing DynamoDB access: {e}")
130+
except Exception as e:
131+
print(f"ERROR: {e}")
132+
133+
print(f"\n{'='*60}")
134+
print(f"IAM policy setup complete!")
135+
print(f"{'='*60}")
136+
print(f"\nNext steps:")
137+
print(f"1. Test the GUI backend switch at https://localhost:8118/config")
138+
print(f"2. If still getting errors, wait another 30-60 seconds for IAM propagation")
139+
print(f"3. Verify AWS credentials are using the 'daylily-service' user:")
140+
print(f" aws sts get-caller-identity")
141+
142+
143+
if __name__ == "__main__":
144+
main()
145+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"Version": "2012-10-17",
3+
"Statement": [
4+
{
5+
"Sid": "ZebraDayDynamoDBAccess",
6+
"Effect": "Allow",
7+
"Action": [
8+
"dynamodb:GetItem",
9+
"dynamodb:PutItem",
10+
"dynamodb:DeleteItem",
11+
"dynamodb:Query",
12+
"dynamodb:DescribeTable",
13+
"dynamodb:CreateTable",
14+
"dynamodb:TagResource"
15+
],
16+
"Resource": "arn:aws:dynamodb:us-west-2:108782052779:table/zebra-day-config"
17+
},
18+
{
19+
"Sid": "ZebraDayDynamoDBListTables",
20+
"Effect": "Allow",
21+
"Action": "dynamodb:ListTables",
22+
"Resource": "*"
23+
},
24+
{
25+
"Sid": "ZebraDayS3BackupAccess",
26+
"Effect": "Allow",
27+
"Action": [
28+
"s3:PutObject",
29+
"s3:GetObject",
30+
"s3:ListBucket",
31+
"s3:HeadBucket"
32+
],
33+
"Resource": [
34+
"arn:aws:s3:::zebra-day-cfg-*",
35+
"arn:aws:s3:::zebra-day-cfg-*/zebra-day/*"
36+
]
37+
},
38+
{
39+
"Sid": "ZebraDayS3BucketCreation",
40+
"Effect": "Allow",
41+
"Action": [
42+
"s3:CreateBucket",
43+
"s3:PutBucketTagging"
44+
],
45+
"Resource": "arn:aws:s3:::zebra-day-cfg-*"
46+
}
47+
]
48+
}
49+

0 commit comments

Comments
 (0)