Skip to content

Commit 23bc092

Browse files
authored
Merge pull request #1490 from gruntwork-io/get-iam-policy-document
add function to retrieve latest version of a policy document
2 parents 23c1dec + 50c33a0 commit 23bc092

2 files changed

Lines changed: 105 additions & 0 deletions

File tree

modules/aws/iam.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package aws
22

33
import (
44
"context"
5+
"fmt"
6+
"net/url"
57
"time"
68

79
"github.com/aws/aws-sdk-go-v2/aws"
@@ -59,6 +61,57 @@ func GetIamCurrentUserArnE(t testing.TestingT) (string, error) {
5961
return *resp.User.Arn, nil
6062
}
6163

64+
// GetIamPolicyDocument gets the most recent policy (JSON) document for an IAM policy.
65+
func GetIamPolicyDocument(t testing.TestingT, region string, policyARN string) string {
66+
out, err := GetIamPolicyDocumentE(t, region, policyARN)
67+
if err != nil {
68+
t.Fatal(err)
69+
}
70+
return out
71+
}
72+
73+
// GetIamPolicyDocumentE gets the most recent policy (JSON) document for an IAM policy.
74+
func GetIamPolicyDocumentE(t testing.TestingT, region string, policyARN string) (string, error) {
75+
iamClient, err := NewIamClientE(t, region)
76+
if err != nil {
77+
return "", err
78+
}
79+
80+
versions, err := iamClient.ListPolicyVersions(context.Background(), &iam.ListPolicyVersionsInput{
81+
PolicyArn: &policyARN,
82+
})
83+
if err != nil {
84+
return "", err
85+
}
86+
87+
var defaultVersion string
88+
for _, version := range versions.Versions {
89+
if version.IsDefaultVersion == true {
90+
defaultVersion = *version.VersionId
91+
}
92+
}
93+
94+
document, err := iamClient.GetPolicyVersion(context.Background(), &iam.GetPolicyVersionInput{
95+
PolicyArn: aws.String(policyARN),
96+
VersionId: aws.String(defaultVersion),
97+
})
98+
if err != nil {
99+
return "", err
100+
}
101+
102+
unescapedDocument := document.PolicyVersion.Document
103+
if unescapedDocument == nil {
104+
return "", fmt.Errorf("no policy document found for policy %s", policyARN)
105+
}
106+
107+
escapedDocument, err := url.QueryUnescape(*unescapedDocument)
108+
if err != nil {
109+
return "", err
110+
}
111+
112+
return escapedDocument, nil
113+
}
114+
62115
// CreateMfaDevice creates an MFA device using the given IAM client.
63116
func CreateMfaDevice(t testing.TestingT, iamClient *iam.Client, deviceName string) *types.VirtualMFADevice {
64117
mfaDevice, err := CreateMfaDeviceE(t, iamClient, deviceName)

modules/aws/iam_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
package aws
22

33
import (
4+
"context"
5+
"strings"
46
"testing"
57

8+
"github.com/aws/aws-sdk-go-v2/aws"
9+
"github.com/aws/aws-sdk-go-v2/service/iam"
10+
"github.com/gruntwork-io/terratest/modules/random"
611
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
713
)
814

915
func TestGetIamCurrentUserName(t *testing.T) {
@@ -19,3 +25,49 @@ func TestGetIamCurrentUserArn(t *testing.T) {
1925
username := GetIamCurrentUserArn(t)
2026
assert.Regexp(t, "^arn:aws:iam::[0-9]{12}:user/.+$", username)
2127
}
28+
29+
func TestGetIAMPolicyDocument(t *testing.T) {
30+
t.Parallel()
31+
32+
region := GetRandomRegion(t, nil, nil)
33+
34+
t.Run("Exists", func(t *testing.T) {
35+
iamClient, err := NewIamClientE(t, region)
36+
require.NoError(t, err)
37+
38+
policyDocument := `{
39+
"Version": "2012-10-17",
40+
"Statement": [
41+
{
42+
"Sid": "Stmt1530709892083",
43+
"Action": "*",
44+
"Effect": "Allow",
45+
"Resource": "*"
46+
}
47+
]
48+
}`
49+
input := &iam.CreatePolicyInput{
50+
PolicyName: aws.String(strings.ToLower(random.UniqueId())),
51+
PolicyDocument: aws.String(policyDocument),
52+
}
53+
policy, err := iamClient.CreatePolicy(context.Background(), input)
54+
require.NoError(t, err)
55+
56+
t.Cleanup(func() {
57+
t.Log("Deleting IAM Policy Document")
58+
_, err := iamClient.DeletePolicy(context.Background(), &iam.DeletePolicyInput{
59+
PolicyArn: policy.Policy.Arn,
60+
})
61+
require.NoError(t, err)
62+
})
63+
64+
p := GetIamPolicyDocument(t, region, *policy.Policy.Arn)
65+
t.Log("Retrieved Policy Document:", p)
66+
assert.JSONEq(t, policyDocument, p)
67+
})
68+
69+
t.Run("DoesNotExist", func(t *testing.T) {
70+
_, err := GetIamPolicyDocumentE(t, region, "arn:aws:iam::1234567890:policy/does-not-exist")
71+
require.Error(t, err)
72+
})
73+
}

0 commit comments

Comments
 (0)