Skip to content

Commit

Permalink
Merge pull request #88 from nrosenberg1/custom-tags-feat
Browse files Browse the repository at this point in the history
Allow custom AWS tags in iamrole annotation
nrosenberg1 authored Mar 16, 2022
2 parents feddadf + eebe8d9 commit ad071d7
Showing 8 changed files with 151 additions and 4 deletions.
18 changes: 18 additions & 0 deletions controllers/iamrole_controller.go
Original file line number Diff line number Diff line change
@@ -298,6 +298,24 @@ func (r *IamroleReconciler) ConstructCreateIAMRoleInput(ctx context.Context, iam
tags["Cluster"] = config.Props.ClusterName()
}

// Custom tags value should be a string of comma seperated key/value pairs
// example annotation: "iammanager.keikoproj.io/tags": "key1=value1;;key2=value2"
if ok, customTagsString := utils.ParseTagsAnnotation(ctx, iamRole); ok {
// Retrieve each key/value pair
keyValueList := strings.Split(customTagsString, ";;")
for _, entry := range keyValueList {
// Should get slice of [key,value]
keyValuePair := strings.Split(entry, "=")
// Make sure tag is formatted correctly as "key=value"
if len(keyValuePair) == 2 {
// Make sure default tags are not overwritten, for duplicate keys the first will be applied
if _, ok = tags[keyValuePair[0]]; !ok {
tags[keyValuePair[0]] = keyValuePair[1]
}
}
}
}

input := &awsapi.IAMRoleRequest{
Name: roleName,
PolicyName: config.InlinePolicyName,
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -5,19 +5,20 @@ go 1.12
require (
github.com/aws/aws-sdk-go v1.25.38
github.com/go-logr/logr v0.1.0
github.com/golang/mock v1.5.0
github.com/golang/mock v1.6.0
github.com/onsi/ginkgo v1.11.0
github.com/onsi/gomega v1.8.1
github.com/pborman/uuid v1.2.0
github.com/pkg/errors v0.8.1
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect
golang.org/x/tools v0.1.1 // indirect
golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7 // indirect
golang.org/x/tools v0.1.9 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
k8s.io/api v0.17.2
k8s.io/apimachinery v0.17.2
k8s.io/client-go v0.17.2
k8s.io/klog v1.0.0
rsc.io/quote/v3 v3.1.0 // indirect
sigs.k8s.io/controller-runtime v0.5.2
sigs.k8s.io/controller-tools v0.2.5 // indirect
)
40 changes: 40 additions & 0 deletions go.sum

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions internal/config/constants.go
Original file line number Diff line number Diff line change
@@ -67,4 +67,6 @@ const (
IRSAAnnotation = "iam.amazonaws.com/irsa-service-account"

IamManagerPrivilegedNamespaceAnnotation = "iammanager.keikoproj.io/privileged"

IamManagerTagsAnnotation = "iammanager.keikoproj.io/tags"
)
5 changes: 5 additions & 0 deletions internal/utils/utils.go
Original file line number Diff line number Diff line change
@@ -193,3 +193,8 @@ func ParsePrivilegedAnnotation(ctx context.Context, ns *v1.Namespace) bool {
}
return false
}

//ParseTagsAnnotation parses IamRole tags annotation and responds if annotation exists
func ParseTagsAnnotation(ctx context.Context, iamRole *iammanagerv1alpha1.Iamrole) (bool, string) {
return parseAnnotations(ctx, config.IamManagerTagsAnnotation, iamRole.Annotations)
}
2 changes: 1 addition & 1 deletion internal/utils/utils_test.go
Original file line number Diff line number Diff line change
@@ -680,7 +680,7 @@ func (s *UtilsTestSuite) TestGenerateNameFunctionBadTemplate(c *check.C) {
}
_, err = utils.GenerateRoleName(s.ctx, resource, *config.Props, &ns)
c.Assert(err, check.NotNil)
c.Assert(err.Error(), check.Matches, ".*unexpected bad character.*")
c.Assert(err.Error(), check.Matches, ".*bad character.*")
}

func (s *UtilsTestSuite) TestGenerateNameFunctionBadObjectReference(c *check.C) {
34 changes: 34 additions & 0 deletions pkg/validation/validate.go
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/keikoproj/iam-manager/api/v1alpha1"
"github.com/keikoproj/iam-manager/internal/config"
@@ -115,6 +116,11 @@ func CompareRole(ctx context.Context, request awsapi.IAMRoleRequest, targetRole
return false
}

//Step 4: Compare Tags
if !CompareTags(ctx, request.Tags, targetRole.Role.Tags) {
return false
}

return true
}

@@ -168,6 +174,34 @@ func CompareAssumeRolePolicy(ctx context.Context, request string, target string)
return true
}

//CompareTags compares tags from request and response
func CompareTags(ctx context.Context, request map[string]string, target []*iam.Tag) bool {
log := log.Logger(ctx, "pkg.validation", "CompareTags")
log.Info("start CompareTags")

var targetTags map[string]string
if len(target) > 0 {
targetTags = make(map[string]string)
if target != nil {
for _, tag := range target {
if tag != nil && tag.Key != nil && tag.Value != nil && aws.StringValue(tag.Key) != "" {
key := aws.StringValue(tag.Key)
value := aws.StringValue(tag.Value)
targetTags[key] = value
}
}
}
}

//compare
if !reflect.DeepEqual(request, targetTags) {
log.Info("input tags and target tags are NOT equal", "req", request, "dest", targetTags)
return false
}

return true
}

//ContainsString Helper functions to check from a slice of strings.
func ContainsString(slice []string, s string) bool {
for _, item := range slice {
47 changes: 47 additions & 0 deletions pkg/validation/validate_test.go
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ package validation_test
import (
"context"
"encoding/json"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/golang/mock/gomock"
"github.com/keikoproj/iam-manager/api/v1alpha1"
@@ -430,6 +431,52 @@ func (s *ValidateSuite) TestCompareAssumeRolePolicyFailure(c *check.C) {
c.Assert(flag, check.Equals, false)
}

func (s *ValidateSuite) TestCompareTagsSuccess(c *check.C) {
input1 := map[string]string{
"cluster": "clusterName",
"managedBy": "iam-manager",
"customTag": "customValue",
}
input2 := []*iam.Tag{
{
Key: aws.String("cluster"),
Value: aws.String("clusterName"),
},
{
Key: aws.String("managedBy"),
Value: aws.String("iam-manager"),
},
{
Key: aws.String("customTag"),
Value: aws.String("customValue"),
},
}

flag := validation.CompareTags(s.ctx, input1, input2)
c.Assert(flag, check.Equals, true)
}

func (s *ValidateSuite) TestCompareTagsFailure(c *check.C) {
input1 := map[string]string{
"cluster": "clusterName",
"managedBy": "iam-manager",
"customTag": "customValue",
}
input2 := []*iam.Tag{
{
Key: aws.String("cluster"),
Value: aws.String("clusterName"),
},
{
Key: aws.String("managedBy"),
Value: aws.String("iam-manager"),
},
}

flag := validation.CompareTags(s.ctx, input1, input2)
c.Assert(flag, check.Equals, false)
}

func (s *ValidateSuite) TestContainsStringSuccess(c *check.C) {
resp := validation.ContainsString([]string{"iamrole.finalizers.iammanager.keikoproj.io", "iamrole.finalizers2.iammanager.keikoproj.io"}, "iamrole.finalizers.iammanager.keikoproj.io")
c.Assert(resp, check.Equals, true)

0 comments on commit ad071d7

Please sign in to comment.