mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-22 12:16:52 +00:00
fix: reject PermissionsBoundary on CreateRole and CreateUser (#944)
This commit is contained in:
@@ -44,6 +44,10 @@ func (s *IAMServiceImpl) CreateRole(accountID string, input *iam.CreateRoleInput
|
||||
return nil, errors.New(awserrors.ErrorIAMInvalidInput)
|
||||
}
|
||||
|
||||
if err := validatePermissionsBoundary(input.PermissionsBoundary); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
path := "/"
|
||||
if input.Path != nil {
|
||||
path = *input.Path
|
||||
|
||||
@@ -108,6 +108,48 @@ func TestCreateRole_InvalidPath(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), awserrors.ErrorIAMInvalidInput)
|
||||
}
|
||||
|
||||
func TestCreateRole_PermissionsBoundarySet(t *testing.T) {
|
||||
svc := setupTestIAMService(t)
|
||||
|
||||
_, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{
|
||||
RoleName: aws.String("bounded-role"),
|
||||
AssumeRolePolicyDocument: aws.String(validTrustPolicy()),
|
||||
PermissionsBoundary: aws.String("arn:aws:iam::" + testAccountID + ":policy/deny-all"),
|
||||
})
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), awserrors.ErrorValidationError)
|
||||
assert.Contains(t, err.Error(), "PermissionsBoundary")
|
||||
|
||||
_, err = svc.GetRole(testAccountID, &iam.GetRoleInput{RoleName: aws.String("bounded-role")})
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), awserrors.ErrorIAMNoSuchEntity)
|
||||
}
|
||||
|
||||
func TestCreateRole_PermissionsBoundaryAbsent(t *testing.T) {
|
||||
svc := setupTestIAMService(t)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
roleName string
|
||||
boundary *string
|
||||
}{
|
||||
{name: "nil", roleName: "nil-boundary", boundary: nil},
|
||||
{name: "empty string", roleName: "empty-boundary", boundary: aws.String("")},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
out, err := svc.CreateRole(testAccountID, &iam.CreateRoleInput{
|
||||
RoleName: aws.String(tt.roleName),
|
||||
AssumeRolePolicyDocument: aws.String(validTrustPolicy()),
|
||||
PermissionsBoundary: tt.boundary,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.roleName, *out.Role.RoleName)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateRole_MalformedTrustPolicy_InvalidJSON(t *testing.T) {
|
||||
svc := setupTestIAMService(t)
|
||||
|
||||
|
||||
@@ -323,6 +323,10 @@ func (s *IAMServiceImpl) CreateUser(accountID string, input *iam.CreateUserInput
|
||||
return nil, errors.New(awserrors.ErrorIAMInvalidInput)
|
||||
}
|
||||
|
||||
if err := validatePermissionsBoundary(input.PermissionsBoundary); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
path := "/"
|
||||
if input.Path != nil {
|
||||
path = *input.Path
|
||||
@@ -1984,6 +1988,17 @@ func validatePolicyName(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// validatePermissionsBoundary rejects a boundary the evaluator cannot enforce.
|
||||
// Storing an identity with an unenforced boundary would widen access silently,
|
||||
// so the create fails visibly instead.
|
||||
func validatePermissionsBoundary(boundary *string) error {
|
||||
if aws.StringValue(boundary) == "" {
|
||||
return nil
|
||||
}
|
||||
return awserrors.Errorf(awserrors.ErrorValidationError,
|
||||
"PermissionsBoundary is not supported in this release; omit it and scope the identity with its attached policies instead")
|
||||
}
|
||||
|
||||
func validatePath(path string) error {
|
||||
if !strings.HasPrefix(path, "/") || !strings.HasSuffix(path, "/") {
|
||||
return fmt.Errorf("path must begin and end with /")
|
||||
|
||||
@@ -91,6 +91,46 @@ func TestCreateUser_Duplicate(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), awserrors.ErrorIAMEntityAlreadyExists)
|
||||
}
|
||||
|
||||
func TestCreateUser_PermissionsBoundarySet(t *testing.T) {
|
||||
svc := setupTestIAMService(t)
|
||||
|
||||
_, err := svc.CreateUser(testAccountID, &iam.CreateUserInput{
|
||||
UserName: aws.String("boundeduser"),
|
||||
PermissionsBoundary: aws.String("arn:aws:iam::" + testAccountID + ":policy/deny-all"),
|
||||
})
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), awserrors.ErrorValidationError)
|
||||
assert.Contains(t, err.Error(), "PermissionsBoundary")
|
||||
|
||||
_, err = svc.GetUser(testAccountID, &iam.GetUserInput{UserName: aws.String("boundeduser")})
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), awserrors.ErrorIAMNoSuchEntity)
|
||||
}
|
||||
|
||||
func TestCreateUser_PermissionsBoundaryAbsent(t *testing.T) {
|
||||
svc := setupTestIAMService(t)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
userName string
|
||||
boundary *string
|
||||
}{
|
||||
{name: "nil", userName: "nilboundary", boundary: nil},
|
||||
{name: "empty string", userName: "emptyboundary", boundary: aws.String("")},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
out, err := svc.CreateUser(testAccountID, &iam.CreateUserInput{
|
||||
UserName: aws.String(tt.userName),
|
||||
PermissionsBoundary: tt.boundary,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.userName, *out.User.UserName)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUser(t *testing.T) {
|
||||
svc := setupTestIAMService(t)
|
||||
createTestUser(t, svc, "getuser")
|
||||
|
||||
Reference in New Issue
Block a user