Skip to content

Commit

Permalink
Merge pull request #73 from Nextdoor/prefix_tweak
Browse files Browse the repository at this point in the history
Implement a configurable pattern for the IAM Role Name
mnkg561 authored Feb 2, 2021
2 parents f9c86d2 + 6103fa4 commit 420573a
Showing 14 changed files with 301 additions and 121 deletions.
36 changes: 27 additions & 9 deletions .github/DEVELOPER.md
Original file line number Diff line number Diff line change
@@ -8,15 +8,33 @@
* kubebuilder

### Quickstart
```
$ git clone https://github.com/keikoproj/iam-manager
$ cd iam-manager
$ go mod
$ go vendor
```

First, go and fork the Github repo to your own personal project. Once that's
done, set up a local build environment off of the original Github repo. Then we
add in your fork'ed repo as a new target for doing git pushes.

$ go clean -modcache
$ go get -v github.com/keikoproj/iam-manager
$ cd "$(go env GOPATH)/src/github.com/keikoproj/iam-manager"
$ make test
$ go mod vendor
$ git remote add myfork <your fork>

### Install Kubebuilder

Kubebuilder is a requirement for the testsuite.. you can install it quickly
on your own or with our make target:

$ make kubebuilder

### Build project
```
$ make
```

$ make

### Running Tests

There are several environment variables that must be set in order for the
test suite to work. The [Makefile](/Makefile) sets these for you, so please
use the `make test` target to run tests:

$ make test
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -15,7 +15,8 @@
vendor/
mocks/
gomock*/
kubebuilder*

#IDE files
.idea/
bin/
bin/
4 changes: 1 addition & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -19,9 +19,7 @@ before_install: skip

install:
# install kube builder so BDD test cases can work
- wget https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.2.0/kubebuilder_2.2.0_linux_amd64.tar.gz
- tar -zxvf kubebuilder_2.2.0_linux_amd64.tar.gz
- sudo mv kubebuilder_2.2.0_linux_amd64 /usr/local/kubebuilder
- make kubebuilder

jobs:
include:
59 changes: 42 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,30 +1,43 @@

# Image URL to use all building/pushing image targets
IMG ?= keikoproj/iam-manager:latest
IMG ?= keikoproj/iam-manager:latest

# Tools required to run the full suite of tests properly
OSNAME ?= $(shell uname -s | tr A-Z a-z)
KUBEBUILDER_VER ?= 2.2.0
KUBEBUILDER_ARCH ?= amd64

# Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
CRD_OPTIONS ?= "crd:trivialVersions=true"

KUBECONFIG ?= $(HOME)/.kube/config
LOCAL ?= true
ALLOWED_POLICY_ACTION ?= s3:,sts:,ec2:Describe,acm:Describe,acm:List,acm:Get,route53:Get,route53:List,route53:Create,route53:Delete,route53:Change,kms:Decrypt,kms:Encrypt,kms:ReEncrypt,kms:GenerateDataKey,kms:DescribeKey,dynamodb:,secretsmanager:GetSecretValue,es:,sqs:SendMessage,sqs:ReceiveMessage,sqs:DeleteMessage,SNS:Publish,sqs:GetQueueAttributes,sqs:GetQueueUrl
RESTRICTED_POLICY_RESOURCES ?= policy-resource
RESTRICTED_S3_RESOURCES ?= s3-resource
AWS_ACCOUNT_ID ?= 123456789012
AWS_REGION ?= us-west-2
MANAGED_POLICIES ?= arn:aws:iam::123456789012:policy/SOMETHING
MANAGED_PERMISSION_BOUNDARY_POLICY ?= arn:aws:iam::1123456789012:role/iam-manager-permission-boundary
CLUSTER_NAME ?= k8s_test_keiko
CLUSTER_OIDC_ISSUER_URL ?= https://google.com/OIDC
DEFAULT_TRUST_POLICY ?= '{"Version": "2012-10-17", "Statement": [{"Effect": "Allow","Principal": {"Federated": "arn:aws:iam::AWS_ACCOUNT_ID:oidc-provider/OIDC_PROVIDER"},"Action": "sts:AssumeRoleWithWebIdentity","Condition": {"StringEquals": {"OIDC_PROVIDER:sub": "system:serviceaccount:{{.NamespaceName}}:SERVICE_ACCOUNT_NAME"}}}, {"Effect": "Allow","Principal": {"AWS": ["arn:aws:iam::{{.AccountID}}:role/trust_role"]},"Action": "sts:AssumeRole"}]}'

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
GOBIN=$(shell go env GOPATH)/bin
GOBIN := $(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
GOBIN := $(shell go env GOBIN)
endif

all: manager

setup: ; $(info $(M) setting up env variables for test…) @ ## Setup env variables
export LOCAL=true
export ALLOWED_POLICY_ACTION=s3:,sts:,ec2:Describe,acm:Describe,acm:List,acm:Get,route53:Get,route53:List,route53:Create,route53:Delete,route53:Change,kms:Decrypt,kms:Encrypt,kms:ReEncrypt,kms:GenerateDataKey,kms:DescribeKey,dynamodb:,secretsmanager:GetSecretValue,es:,sqs:SendMessage,sqs:ReceiveMessage,sqs:DeleteMessage,SNS:Publish,sqs:GetQueueAttributes,sqs:GetQueueUrl
export RESTRICTED_POLICY_RESOURCES=policy-resource
export RESTRICTED_S3_RESOURCES=s3-resource
export AWS_ACCOUNT_ID=123456789012
export AWS_REGION=us-west-2
export MANAGED_POLICIES=arn:aws:iam::123456789012:policy/SOMETHING
export MANAGED_PERMISSION_BOUNDARY_POLICY=arn:aws:iam::1123456789012:role/iam-manager-permission-boundary
export CLUSTER_NAME=k8s_test_keiko
export CLUSTER_OIDC_ISSUER_URL=https://google.com/OIDC
export DEFAULT_TRUST_POLICY={"Version": "2012-10-17", "Statement": [{"Effect": "Allow","Principal": {"Federated": "arn:aws:iam::AWS_ACCOUNT_ID:oidc-provider/OIDC_PROVIDER"},"Action": "sts:AssumeRoleWithWebIdentity","Condition": {"StringEquals": {"OIDC_PROVIDER:sub": "system:serviceaccount:{{.NamespaceName}}:SERVICE_ACCOUNT_NAME"}}}, {"Effect": "Allow","Principal": {"AWS": ["arn:aws:iam::{{.AccountID}}:role/trust_role"]},"Action": "sts:AssumeRole"}]}
.PHONY: kubebuilder
kubebuilder:
@echo "Downloading and installing Kubebuilder - this requires sudo privileges"
curl -fsSL -O "https://github.com/kubernetes-sigs/kubebuilder/releases/download/v$(KUBEBUILDER_VER)/kubebuilder_$(KUBEBUILDER_VER)_$(OSNAME)_$(KUBEBUILDER_ARCH).tar.gz"
rm -rf kubebuilder && mkdir -p kubebuilder
tar -zxvf kubebuilder_$(KUBEBUILDER_VER)_$(OSNAME)_$(KUBEBUILDER_ARCH).tar.gz --strip-components 1 -C kubebuilder
sudo cp -rf kubebuilder /usr/local

mock:
go get -u github.com/golang/mock/mockgen
@@ -34,7 +47,19 @@ mock:
done

# Run tests
test: setup mock generate fmt manifests
test: mock generate fmt manifests
KUBECONFIG=$(KUBECONFIG) \
LOCAL=$(LOCAL) \
ALLOWED_POLICY_ACTION=$(ALLOWED_POLICY_ACTION) \
RESTRICTED_POLICY_RESOURCES=$(RESTRICTED_POLICY_RESOURCES) \
RESTRICTED_S3_RESOURCES=$(RESTRICTED_S3_RESOURCES) \
AWS_ACCOUNT_ID=$(AWS_ACCOUNT_ID) \
AWS_REGION=$(AWS_REGION) \
MANAGED_POLICIES=$(MANAGED_POLICIES) \
MANAGED_PERMISSION_BOUNDARY_POLICY=$(MANAGED_PERMISSION_BOUNDARY_POLICY) \
CLUSTER_NAME=$(CLUSTER_NAME) \
CLUSTER_OIDC_ISSUER_URL="$(CLUSTER_OIDC_ISSUER_URL)" \
DEFAULT_TRUST_POLICY=$(DEFAULT_TRUST_POLICY) \
go test ./... -coverprofile cover.out

# Build manager binary
29 changes: 20 additions & 9 deletions controllers/iamrole_controller.go
Original file line number Diff line number Diff line change
@@ -73,20 +73,28 @@ func (r *IamroleReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
log := log.Logger(ctx, "controllers", "iamrole_controller", "Reconcile")
log.WithValues("iamrole", req.NamespacedName)
log.Info("Start of the request")

//Get the resource
var iamRole iammanagerv1alpha1.Iamrole

if err := r.Get(ctx, req.NamespacedName, &iamRole); err != nil {
return ctrl.Result{}, ignoreNotFound(err)
}

roleName := fmt.Sprintf("k8s-%s", iamRole.ObjectMeta.Name)

if config.Props.DeriveNameFromNamespace() && config.Props.MaxRolesAllowed() == 1 {
roleName = fmt.Sprintf("k8s-%s", iamRole.ObjectMeta.Namespace)
// TODO: Remove the need to do this here.
//
// We are generating the roleName here for the potential call to the
// delete function. The right way to do this is to record the created
// IAM role ARN in the IamRole object itself, so that we can then
// guarantee the delete even if the operator has changed their
// iam.role.pattern setting.
roleName, err := utils.GenerateRoleName(ctx, iamRole, *config.Props)
if err != nil {
r.Recorder.Event(&iamRole, v1.EventTypeWarning, string(iammanagerv1alpha1.Error), "Unable to construct iam role name to error "+err.Error())
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}

// Isit being deleted?
// Is it being deleted?
if iamRole.ObjectMeta.DeletionTimestamp.IsZero() {
//Good. This is not Delete use case
//Lets check if this is very first time use case
@@ -132,12 +140,15 @@ func (r *IamroleReconciler) HandleReconcile(ctx context.Context, req ctrl.Reques
log = log.WithValues("iam_role_cr", iamRole.Name)
log.Info("state of the custom resource ", "state", iamRole.Status.State)

roleName := fmt.Sprintf("k8s-%s", iamRole.ObjectMeta.Name)
roleName, err := utils.GenerateRoleName(ctx, *iamRole, *config.Props)

if config.Props.DeriveNameFromNamespace() && config.Props.MaxRolesAllowed() == 1 {
roleName = fmt.Sprintf("k8s-%s", iamRole.ObjectMeta.Namespace)
}
log.V(1).Info("roleName constructed successfully", "roleName", roleName)
if err != nil {
r.Recorder.Event(iamRole, v1.EventTypeWarning, string(iammanagerv1alpha1.Error), "Unable to construct iam role name to error "+err.Error())
// It is not clear to me that we want to requeue here - as this is a fairly permanent
// error. Is there a better pattern here?
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}

input, status, err := r.ConstructCreateIAMRoleInput(ctx, iamRole, roleName)
if err != nil {
1 change: 0 additions & 1 deletion controllers/iamrole_controller_test.go
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@ import (
)

var _ = Describe("IamroleController", func() {

Describe("When checking a StatusUpdatePredicate", func() {
instance := StatusUpdatePredicate{}

48 changes: 42 additions & 6 deletions docs/Configmap_Properties.md
Original file line number Diff line number Diff line change
@@ -8,12 +8,48 @@ This document explains configmap variables.
| aws.accountId | AWS account ID where IAM roles are created| |Optional |
| iam.managed.policies | User managed IAM policies | |Optional |
| iam.managed.permission.boundary.policy| User managed permission boundary policy|k8s-iam-manager-cluster-permission-boundary |Required |
| webhook.enabled | Enable webhook? | false | Required |
| iam.role.max.limit.per.namespace | Maximum number of roles per namespace | 1 | Required |
| aws.region | AWS Region | us-west-2 | Required |
| iam.default.trust.policy| Default trust policy role. This must follow v1alpha1.AssumeRolePolicyDocument syntax| | Optional |
| iam.role.derive.from.namespace | Derive iam role name from namespace? if true it will be k8s-<namespace> | false | Optional|
| webhook.enabled | Enable webhook? | `false | Required |
| iam.role.max.limit.per.namespace | Maximum number of roles per namespace | 1 | Required |
| aws.region | AWS Region | `us-west-2` | Required |
| iam.default.trust.policy | Default trust policy role. This must follow v1alpha1.AssumeRolePolicyDocument syntax| | Optional |
| [iam.role.pattern](#iamrolepattern) | See docs below... | `k8s-{{ .ObjectMeta.Name }}` | Optional |
| controller.desired.frequency | Controller frequency to check the state of the world (in seconds) | 300 | Optional |
| k8s.cluster.name | Name of the cluster | | Optional |
| k8s.cluster.oidc.issuer.url | OIDC issuer of the cluster | | Optional |
| iam.irsa.enabled | Enable IRSA option? | false | Optional |
| iam.irsa.enabled | Enable IRSA option? | `false` | Optional |


## `iam.role.pattern`

[template]: https://golang.org/pkg/text/template/
[iamrole]: /api/v1alpha1/iamrole_types.go

_Default_: `k8s-{{ .ObjectMeta.Name }}`

All IAM roles created by the controller will use this [GoLang template][template]
to generate the final IAM Role Name. The default setting works fine if you have
a single cluster - but if you want to operate multiple clusters in the same AWS
account you will need to make sure the controllers do not conflict.

The [`Iamrole`][iamrole] object is passed into the Go templating engine, enabling
you to use any object field found in that role. For example
`mycluster-{{ .ObjectMeta.Namespace }}-{{ .ObjectMeta.Name }}`.

All IAM roles created and managed by the controller will use this prefix. This
helps organize IAM roles within your AWS Account, and can be used to ensure
uniqueness between different EKS Clusters within the same AWS account.

**Critical Note: Read [this](#note-about-changing-iamroleprefix-and-iamroleseparator)
before changing this setting**

**Note: Changes to your IAM Policy may be required if you customize this**

## Note about changing `iam.role.pattern`

If you have existing `IAMRole` resources in your cluster, and you make a change to
the `iam.role.pattern` setting - the controller will reconcile the situation by
creating NEW IAM roles. It will _not_ however clean up the old roles - thus you
will have left over unused IAM roles in your account.

Get these settings right from the beginning, or be prepared to clean up the left
over roles.
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -10,8 +10,9 @@ require (
github.com/onsi/gomega v1.8.1
github.com/pborman/uuid v1.2.0
github.com/pkg/errors v0.8.1
golang.org/x/mod v0.4.0 // indirect
golang.org/x/tools v0.0.0-20201221201019-196535612888 // indirect
golang.org/x/mod v0.4.1 // indirect
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
golang.org/x/tools v0.1.0 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
k8s.io/api v0.17.2
k8s.io/apimachinery v0.17.2
53 changes: 10 additions & 43 deletions go.sum
Original file line number Diff line number Diff line change
@@ -333,10 +333,11 @@ golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -351,11 +352,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
@@ -365,12 +363,10 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -380,25 +376,23 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 h1:+DCIGbF/swA92ohVg0//6X2IVY3KZs6p9mix0ziNYJM=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
@@ -414,38 +408,18 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262 h1:qsl9y/CJx34tuA7QCPNp86JNJe4spst6Ff8MjvPUdPg=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72 h1:bw9doJza/SFBEweII/rHQh338oozWyiFsBRHtrflcws=
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200428140416-006b16f6cf7f h1:S58tgFwC/PUuXkZBbUfGloERWUkLz9WBY3HFy9BMLaM=
golang.org/x/tools v0.0.0-20200428140416-006b16f6cf7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200428204708-317da45f2f19 h1:uU2/31wMz41c/26KcY61Rq5vekiLPBGBXGackzSt4tM=
golang.org/x/tools v0.0.0-20200428204708-317da45f2f19/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32 h1:Xvf3ZQTm5bjXPxhI7g+dwqsCqadK1rcNtwtszuatetk=
golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375 h1:SjQ2+AKWgZLc1xej6WSzL+Dfs5Uyd5xcZH1mGC411IA=
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200526224456-8b020aee10d2 h1:21BqcH/onxtGHn1A2GDOJjZnbt4Nlez629S3eaR+eYs=
golang.org/x/tools v0.0.0-20200526224456-8b020aee10d2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200529172331-a64b76657301 h1:G6CNEgFU8/XwexSnuFw+Jq/WePjRitgy6ofBcPnAIPo=
golang.org/x/tools v0.0.0-20200529172331-a64b76657301/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200530233709-52effbd89c51 h1:Wec8/IO8hAraBf0it7/dPQYOslIrgM938wZYNkLnOYc=
golang.org/x/tools v0.0.0-20200530233709-52effbd89c51/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200606014950-c42cb6316fb6 h1:5Y8c5HBW6hBYnGEE3AbJPV0R8RsQmg1/eaJrpvasns0=
golang.org/x/tools v0.0.0-20200606014950-c42cb6316fb6/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200609164405-eb789aa7ce50 h1:59syOWj4+Fl+op4LL8fX1kO7HmbdEWfxlw4tcGvH+y0=
golang.org/x/tools v0.0.0-20200609164405-eb789aa7ce50/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201221201019-196535612888 h1:7caG9TJP3w/Lk3qVEGny32sb4gFJxPq0nVCYCHGi5Gw=
golang.org/x/tools v0.0.0-20201221201019-196535612888/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210119195117-a46736d9d962 h1:2W5DpBYpoX3ZovvDTg1qC2gXJEa0dXKkZVxUr3xiQdY=
golang.org/x/tools v0.0.0-20210119195117-a46736d9d962/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=
@@ -454,10 +428,8 @@ gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -467,7 +439,6 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -483,9 +454,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -507,7 +476,6 @@ k8s.io/component-base v0.17.2/go.mod h1:zMPW3g5aH7cHJpKYQ/ZsGMcgbsA/VyhEugF3QT1a
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
@@ -525,7 +493,6 @@ rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/controller-runtime v0.5.2 h1:pyXbUfoTo+HA3jeIfr0vgi+1WtmNh0CwlcnQGLXwsSw=
sigs.k8s.io/controller-runtime v0.5.2/go.mod h1:JZUwSMVbxDupo0lTJSSFP5pimEyxGynROImSsqIOx1A=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU=
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
8 changes: 4 additions & 4 deletions internal/config/constants.go
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ const (
propertyAwsRegion = "aws.region"

//enable webhook property
propertAWSAccountID = "aws.accountId"
propertyAWSAccountID = "aws.accountId"

// user managed policies
propertyManagedPolicies = "iam.managed.policies"
@@ -37,12 +37,12 @@ const (
//enable webhook property
propertyWebhookEnabled = "webhook.enabled"

//golang-templated pattern to use for iam role name generation
propertyIamRolePattern = "iam.role.pattern"

//max allowed aws iam roles per namespace
propertyMaxIamRoles = "iam.role.max.limit.per.namespace"

//propertyDeriveNameFromNameSpace is a bool value and can be used to configure the name construction
propertyDeriveNameFromNameSpace = "iam.role.derive.from.namespace"

//propertyDesiredStateFrequency is a configurable param to make sure to check the external state (in seconds). default to 30 mins (1800 seconds)
propertyDesiredStateFrequency = "controller.desired.frequency"

28 changes: 12 additions & 16 deletions internal/config/properties.go
Original file line number Diff line number Diff line change
@@ -28,12 +28,12 @@ type Properties struct {
awsRegion string
isWebhookEnabled string
maxRolesAllowed int
deriveNameFromNamespace string
controllerDesiredFrequency int
clusterName string
isIRSAEnabled string
clusterOIDCIssuerUrl string
defaultTrustPolicy string
iamRolePattern string
}

func init() {
@@ -79,10 +79,10 @@ func LoadProperties(env string, cm ...*v1.ConfigMap) error {
managedPermissionBoundaryPolicy: os.Getenv("MANAGED_PERMISSION_BOUNDARY_POLICY"),
awsRegion: os.Getenv("AWS_REGION"),
isWebhookEnabled: os.Getenv("ENABLE_WEBHOOK"),
deriveNameFromNamespace: os.Getenv("DERIVE_NAME_FROM_NAMESPACE"),
clusterName: os.Getenv("CLUSTER_NAME"),
clusterOIDCIssuerUrl: os.Getenv("CLUSTER_OIDC_ISSUER_URL"),
defaultTrustPolicy: os.Getenv("DEFAULT_TRUST_POLICY"),
iamRolePattern: os.Getenv("IAM_ROLE_PATTERN"),
}
return nil
}
@@ -113,13 +113,6 @@ func LoadProperties(env string, cm ...*v1.ConfigMap) error {
Props.isWebhookEnabled = "false"
}

deriveNameFromNS := cm[0].Data[propertyDeriveNameFromNameSpace]
if deriveNameFromNS == "true" {
Props.deriveNameFromNamespace = "true"
} else {
Props.deriveNameFromNamespace = "false"
}

awsRegion := cm[0].Data[propertyAwsRegion]
if awsRegion != "" {
Props.awsRegion = awsRegion
@@ -149,7 +142,7 @@ func LoadProperties(env string, cm ...*v1.ConfigMap) error {
Props.controllerDesiredFrequency = 1800
}

awsAccountID := cm[0].Data[propertAWSAccountID]
awsAccountID := cm[0].Data[propertyAWSAccountID]
// Load AWS account ID
if Props.awsAccountID == "" && awsAccountID == "" {
awsAccountID, err := awsapi.NewSTS(Props.awsRegion).GetAccountID(context.Background())
@@ -161,6 +154,13 @@ func LoadProperties(env string, cm ...*v1.ConfigMap) error {
Props.awsAccountID = awsAccountID
}

iamRolePattern := cm[0].Data[propertyIamRolePattern]
if iamRolePattern == "" {
Props.iamRolePattern = "k8s-{{ .ObjectMeta.Name }}"
} else {
Props.iamRolePattern = iamRolePattern
}

managedPermissionBoundaryPolicyArn := cm[0].Data[propertyPermissionBoundary]

if managedPermissionBoundaryPolicyArn == "" {
@@ -243,12 +243,8 @@ func (p *Properties) IsWebHookEnabled() bool {
return resp
}

func (p *Properties) DeriveNameFromNamespace() bool {
resp := false
if p.deriveNameFromNamespace == "true" {
resp = true
}
return resp
func (p *Properties) IamRolePattern() string {
return p.iamRolePattern
}

func (p *Properties) MaxRolesAllowed() int {
14 changes: 4 additions & 10 deletions internal/config/properties_test.go
Original file line number Diff line number Diff line change
@@ -88,9 +88,9 @@ func (s *PropertiesSuite) TestLoadPropertiesSuccessWithDefaults(c *check.C) {
c.Assert(Props.MaxRolesAllowed(), check.Equals, 1)
c.Assert(Props.ControllerDesiredFrequency(), check.Equals, 1800)
c.Assert(Props.IsWebHookEnabled(), check.Equals, false)
c.Assert(Props.DeriveNameFromNamespace(), check.Equals, false)
c.Assert(Props.AWSAccountID(), check.Equals, "123456789012")
c.Assert(strings.HasPrefix(Props.ManagedPermissionBoundaryPolicy(), "arn:aws:iam:"), check.Equals, true)
c.Assert(Props.IamRolePattern(), check.Equals, "k8s-{{ .ObjectMeta.Name }}")
//when an emty string passed split strings gives you array of 1 with ""
c.Assert(len(Props.ManagedPolicies()), check.Equals, 1)
c.Assert(Props.ManagedPolicies()[0], check.Equals, "")
@@ -103,8 +103,7 @@ func (s *PropertiesSuite) TestLoadPropertiesSuccessWithDefaultsManagedPoliciesWi
Data: map[string]string{
"iam.managed.permission.boundary.policy": "iam-manager-permission-boundary",
"aws.accountId": "123456789012",
"iam.managed.policies": "DescribeEC2",

"iam.managed.policies": "DescribeEC2",
},
}
err := LoadProperties("", cm)
@@ -113,7 +112,6 @@ func (s *PropertiesSuite) TestLoadPropertiesSuccessWithDefaultsManagedPoliciesWi
c.Assert(Props.MaxRolesAllowed(), check.Equals, 1)
c.Assert(Props.ControllerDesiredFrequency(), check.Equals, 1800)
c.Assert(Props.IsWebHookEnabled(), check.Equals, false)
c.Assert(Props.DeriveNameFromNamespace(), check.Equals, false)
c.Assert(Props.AWSAccountID(), check.Equals, "123456789012")
c.Assert(strings.HasPrefix(Props.ManagedPermissionBoundaryPolicy(), "arn:aws:iam:"), check.Equals, true)
//when an emty string passed split strings gives you array of 1 with ""
@@ -131,13 +129,14 @@ func (s *PropertiesSuite) TestLoadPropertiesSuccessWithCustom(c *check.C) {
"iam.role.derive.from.namespace": "true",
"controller.desired.frequency": "30",
"iam.role.max.limit.per.namespace": "5",
"iam.role.pattern": "pfx-{{ .ObjectMeta.Name }}",
},
}
err := LoadProperties("", cm)
c.Assert(err, check.IsNil)
c.Assert(Props.MaxRolesAllowed(), check.Equals, 5)
c.Assert(Props.ControllerDesiredFrequency(), check.Equals, 30)
c.Assert(Props.DeriveNameFromNamespace(), check.Equals, true)
c.Assert(Props.IamRolePattern(), check.Equals, "pfx-{{ .ObjectMeta.Name }}")
}

func (s *PropertiesSuite) TestGetAllowedPolicyAction(c *check.C) {
@@ -180,11 +179,6 @@ func (s *PropertiesSuite) TestIsWebhookEnabled(c *check.C) {
c.Assert(value, check.Equals, false)
}

func (s *PropertiesSuite) TestDeriveNameFromNamespace(c *check.C) {
value := Props.DeriveNameFromNamespace()
c.Assert(value, check.Equals, false)
}

func (s *PropertiesSuite) TestControllerDesiredFrequency(c *check.C) {
value := Props.ControllerDesiredFrequency()
c.Assert(value, check.Equals, 0)
25 changes: 25 additions & 0 deletions internal/utils/utils.go
Original file line number Diff line number Diff line change
@@ -125,3 +125,28 @@ func DefaultTrustPolicy(ctx context.Context, trustPolicyDoc string, ns string) (

return &trustPolicy, nil
}

// GenerateRoleName returns a roleName that should be created in IAM using
// the supplied iam.role.pattern. This pattern can be customized by the
// end-user.
func GenerateRoleName(ctx context.Context, iamRole iammanagerv1alpha1.Iamrole, props config.Properties) (string, error) {
log := log.Logger(ctx, "internal.utils.utils", "GenerateRoleNam")
tmpl, err := template.New("rolename").Parse(props.IamRolePattern())
if err != nil {
msg := "unable to parse supplied iam.role.pattern"
log.Error(err, msg)
return "", err
}

// Write the template output into a buffer and then grab that as a string.
// There is no way in GoLang natively to do this.
buf := &bytes.Buffer{}
err = tmpl.ExecuteTemplate(buf, "rolename", iamRole)
if err != nil {
msg := "unable to execute iam.role.pattern template against the iamrole object"
log.Error(err, msg)
return "", err
}

return buf.String(), nil
}
109 changes: 109 additions & 0 deletions internal/utils/utils_test.go
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import (
"github.com/keikoproj/iam-manager/internal/config"
"github.com/keikoproj/iam-manager/internal/utils"
"gopkg.in/check.v1"
v12 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"testing"
)
@@ -26,6 +27,13 @@ func TestUtilsTestSuite(t *testing.T) {
func (s *UtilsTestSuite) SetUpTest(c *check.C) {
s.ctx = context.Background()
s.mockCtrl = gomock.NewController(s.t)

// Always reset the config.Props between tests - we make changes to them
// during certain tests, and we want to ensure that they are predictable
// between each test.
config.Props = nil
err := config.LoadProperties("LOCAL")
c.Assert(err, check.IsNil)
}

func (s *UtilsTestSuite) TearDownTest(c *check.C) {
@@ -516,3 +524,104 @@ func (s *UtilsTestSuite) TestGetTrustPolicyWithIRSAAnnotationAndServiceRoleInReq
c.Assert(roleString, check.Equals, string(expected))

}

func (s *UtilsTestSuite) TestGenerateNameFunction(c *check.C) {
cm := &v12.ConfigMap{
Data: map[string]string{
"aws.accountId": "123456789012", // Required mock for testing
"iam.role.derive.from.namespace": "false",
"iam.role.pattern": "pfx+{{ .ObjectMeta.Name }}",
},
}
config.Props = nil
err := config.LoadProperties("", cm)
c.Assert(err, check.IsNil)

resource := &v1alpha1.Iamrole{
ObjectMeta: v1.ObjectMeta{
Name: "foo",
Namespace: "test-ns",
},
}
name, err := utils.GenerateRoleName(s.ctx, *resource, *config.Props)
c.Assert(name, check.Equals, "pfx+foo")
c.Assert(err, check.IsNil)
}

func (s *UtilsTestSuite) TestGenerateNameFunctionWithNamespace(c *check.C) {
cm := &v12.ConfigMap{
Data: map[string]string{
"aws.accountId": "123456789012", // Required mock for testing
"iam.role.derive.from.namespace": "true",
"iam.role.pattern": "pfx+{{ .ObjectMeta.Namespace}}+{{ .ObjectMeta.Name }}",
},
}
config.Props = nil
err := config.LoadProperties("", cm)
c.Assert(err, check.IsNil)

resource := &v1alpha1.Iamrole{
ObjectMeta: v1.ObjectMeta{
Name: "foo",
Namespace: "test-ns",
},
}
roleName, err := utils.GenerateRoleName(s.ctx, *resource, *config.Props)
c.Assert(roleName, check.Equals, "pfx+test-ns+foo")
c.Assert(err, check.IsNil)
}

func assertPanic(t *testing.T, f func()) {
defer func() {
if r := recover(); r == nil {
t.Errorf("The code did not panic")
}
}()
f()
}

func (s *UtilsTestSuite) TestGenerateNameFunctionBadTemplate(c *check.C) {
cm := &v12.ConfigMap{
Data: map[string]string{
"aws.accountId": "123456789012", // Required mock for testing
"iam.role.derive.from.namespace": "true",
"iam.role.pattern": "pfx+{{ invalid-template }}",
},
}
config.Props = nil
err := config.LoadProperties("", cm)
c.Assert(err, check.IsNil)

resource := &v1alpha1.Iamrole{
ObjectMeta: v1.ObjectMeta{
Name: "foo",
Namespace: "test-ns",
},
}
_, err = utils.GenerateRoleName(s.ctx, *resource, *config.Props)
c.Assert(err, check.NotNil)
c.Assert(err.Error(), check.Matches, ".*unexpected bad character.*")
}

func (s *UtilsTestSuite) TestGenerateNameFunctionBadObjectReference(c *check.C) {
cm := &v12.ConfigMap{
Data: map[string]string{
"aws.accountId": "123456789012", // Required mock for testing
"iam.role.derive.from.namespace": "true",
"iam.role.pattern": "pfx+{{ .invalid.data }}",
},
}
config.Props = nil
err := config.LoadProperties("", cm)
c.Assert(err, check.IsNil)

resource := &v1alpha1.Iamrole{
ObjectMeta: v1.ObjectMeta{
Name: "foo",
Namespace: "test-ns",
},
}
_, err = utils.GenerateRoleName(s.ctx, *resource, *config.Props)
c.Assert(err, check.NotNil)
c.Assert(err.Error(), check.Matches, ".*field invalid in type.*")
}

0 comments on commit 420573a

Please sign in to comment.