Repository: aws-cloudformation/rain
Pull request #217 (2023-12-02 11:45:54)

fix: support IAM user identity in GetCallerArn
## Overview

Changed the ARN returned by GetCallerIdentity to return the IAM Role ARN if it is of the "assume-role" style, otherwise the ARN is returned as is.

## Issue

#216 

## Check

**IAM user**

```sh
$ aws sts get-caller-identity
{
    "UserId": "xxxxxxxxxxxxxxxxxxxxx",
    "Account": "xxxxxxxxxxxx",
    "Arn": "arn:aws:iam::xxxxxxxxxxxx:user/khrmoryz"
}

$ go run cmd/rain/main.go forecast --experimental ./test/templates/success.template s3 --params BucketName=foo
Clear skies! 🌞 All 3 checks passed.
```

**Assume-Role**

```sh
$ aws sts get-caller-identity
{
    "UserId": "xxxxxxxxxxxxxxxxxxxxx:botocore-session-1701516435",
    "Account": "xxxxxxxxxxxx",
    "Arn": "arn:aws:sts::xxxxxxxxxxxx:assumed-role/Admin/botocore-session-1701516435"
}

$ go run cmd/rain/main.go forecast --experimental ./test/templates/success.template s3 --params BucketName=foo
Clear skies! 🌞 All 3 checks passed.
```

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.



Patch:
diff --git a/internal/aws/iam/iam.go b/internal/aws/iam/iam.go
index 2743d2b0..30a3a502 100644
--- a/internal/aws/iam/iam.go
+++ b/internal/aws/iam/iam.go
@@ -30,19 +30,29 @@ func GetCallerArn(config awsgo.Config) (string, error) {
 		fmt.Println("Unable to get caller identity", stsErr)
 		return "", stsErr
 	}
-	// Convert this
-	// arn:aws:sts::755952356119:assumed-role/Admin/ezbeard-Isengard
-	// to this:
-	// arn:aws:iam::755952356119:role/Admin
-	//
-	// Will this work consistently for other SSO providers?
-	// Is there a programmatic way to retrieve the actual role?
-
-	sts := strings.Split(*stsRes.Arn, "sts::")[1]
+	return TransformCallerArn(*stsRes.Arn), nil
+}
+
+func TransformCallerArn(stsResArn string) string {
+	if strings.Split(stsResArn, ":")[2] == "sts" {
+		return convertAssumeRoleToRole(stsResArn)
+	}
+	return stsResArn
+}
+
+// Convert this
+// arn:aws:sts::755952356119:assumed-role/Admin/ezbeard-Isengard
+// to this:
+// arn:aws:iam::755952356119:role/Admin
+//
+// Will this work consistently for other SSO providers?
+// Is there a programmatic way to retrieve the actual role?
+func convertAssumeRoleToRole(stsResArn string) string {
+	sts := strings.Split(stsResArn, "sts::")[1]
 	accountId := strings.Split(sts, ":")[0]
-	assumedRole := strings.Split(*stsRes.Arn, "assumed-role/")[1]
+	assumedRole := strings.Split(stsResArn, "assumed-role/")[1]
 	actualRoleName := strings.Split(assumedRole, "/")[0]
-	return fmt.Sprintf("arn:aws:iam::%v:role/%v", accountId, actualRoleName), nil
+	return fmt.Sprintf("arn:aws:iam::%v:role/%v", accountId, actualRoleName)
 }
 
 // Simulate actions on a resource.


Test patch:
diff --git a/internal/aws/iam/iam_test.go b/internal/aws/iam/iam_test.go
new file mode 100644
index 00000000..f996f88b
--- /dev/null
+++ b/internal/aws/iam/iam_test.go
@@ -0,0 +1,12 @@
+package iam
+
+import "testing"
+
+func TestTransformCallerArn2(t *testing.T) {
+	if TransformCallerArn("arn:aws:sts::755952356119:assumed-role/Admin/khmoryz") != "arn:aws:iam::755952356119:role/Admin" {
+		t.Errorf("Failed to transform assume-role type arn")
+	}
+	if TransformCallerArn("arn:aws:iam::755952356119:user/khmoryz") != "arn:aws:iam::755952356119:user/khmoryz" {
+		t.Errorf("Failed to transform IAM user type arn")
+	}
+}