Skip to content

Commit

Permalink
Merge pull request #157 from ministryofjustice/namespace-restriction-…
Browse files Browse the repository at this point in the history
…regexp-format

Regexp support for namespace restrictions (opt-in)
  • Loading branch information
jrnt30 committed Aug 17, 2018
2 parents ed9f82d + 01008ac commit d531045
Show file tree
Hide file tree
Showing 5 changed files with 325 additions and 113 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ metadata:
```

_Note:_ You can also use glob-based matching for namespace restrictions, which works nicely with the path-based
namespacing supported for AWS IAM roles.
namespacing supported for AWS IAM roles.

Example: to allow all roles prefixed with `my-custom-path/` to be assumed by pods in the default namespace, the
default namespace would be annotated as follows:
Expand All @@ -303,6 +303,19 @@ metadata:
name: default
```

If you prefer `regexp` to glob-based matching you can specify `--namespace-restriction-format=regexp`, then you can
use a `regexp` in your annotation:

```yaml
apiVersion: v1
kind: Namespace
metadata:
annotations:
iam.amazonaws.com/allowed-roles: |
["my-custom-path/.*"]
name: default
```

### RBAC Setup

This is the basic RBAC setup to get kube2iam working correctly when your cluster is using rbac. Below is the bare minimum to get kube2iam working.
Expand Down
1 change: 1 addition & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func addFlags(s *server.Server, fs *pflag.FlagSet) {
fs.BoolVar(&s.AutoDiscoverDefaultRole, "auto-discover-default-role", false, "Queries EC2 Metadata to determine the default Iam Role and base ARN, cannot be used with --default-role, overwrites any previous setting for --base-role-arn")
fs.StringVar(&s.HostInterface, "host-interface", "docker0", "Host interface for proxying AWS metadata")
fs.BoolVar(&s.NamespaceRestriction, "namespace-restrictions", false, "Enable namespace restrictions")
fs.StringVar(&s.NamespaceRestrictionFormat, "namespace-restriction-format", s.NamespaceRestrictionFormat, "Namespace Restriction Format (glob/regexp)")
fs.StringVar(&s.NamespaceKey, "namespace-key", s.NamespaceKey, "Namespace annotation key used to retrieve the IAM roles allowed (value in annotation should be json array)")
fs.StringVar(&s.HostIP, "host-ip", s.HostIP, "IP address of host")
fs.StringVar(&s.NodeName, "node", s.NodeName, "Name of the node where kube2iam is running")
Expand Down
37 changes: 27 additions & 10 deletions mappings/mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package mappings

import (
"fmt"
"regexp"
"strings"

glob "github.com/ryanuber/go-glob"
log "github.com/sirupsen/logrus"
Expand All @@ -13,12 +15,13 @@ import (

// RoleMapper handles relevant logic around associating IPs with a given IAM role
type RoleMapper struct {
defaultRoleARN string
iamRoleKey string
namespaceKey string
namespaceRestriction bool
iam *iam.Client
store store
defaultRoleARN string
iamRoleKey string
namespaceKey string
namespaceRestriction bool
iam *iam.Client
store store
namespaceRestrictionFormat string
}

type store interface {
Expand Down Expand Up @@ -90,10 +93,23 @@ func (r *RoleMapper) checkRoleForNamespace(roleArn string, namespace string) boo
ar := kube2iam.GetNamespaceRoleAnnotation(ns, r.namespaceKey)
for _, rolePattern := range ar {
normalized := r.iam.RoleARN(rolePattern)
if glob.Glob(normalized, roleArn) {
log.Debugf("Role: %s matched %s on namespace:%s.", roleArn, rolePattern, namespace)
return true

if strings.ToLower(r.namespaceRestrictionFormat) == "regexp" {
matched, err := regexp.MatchString(normalized, roleArn)
if err != nil {
log.Errorf("Namespace annotation %s caused an error when trying to match: %s for namespace: %s", rolePattern, roleArn, namespace)
}
if matched {
log.Debugf("Role: %s matched %s on namespace:%s.", roleArn, rolePattern, namespace)
return true
}
} else {
if glob.Glob(normalized, roleArn) {
log.Debugf("Role: %s matched %s on namespace:%s.", roleArn, rolePattern, namespace)
return true
}
}

}
log.Warnf("Role: %s on namespace: %s not found.", roleArn, namespace)
return false
Expand Down Expand Up @@ -131,13 +147,14 @@ func (r *RoleMapper) DumpDebugInfo() map[string]interface{} {
}

// NewRoleMapper returns a new RoleMapper for use.
func NewRoleMapper(roleKey string, defaultRole string, namespaceRestriction bool, namespaceKey string, iamInstance *iam.Client, kubeStore store) *RoleMapper {
func NewRoleMapper(roleKey string, defaultRole string, namespaceRestriction bool, namespaceKey string, iamInstance *iam.Client, kubeStore store, namespaceRestrictionFormat string) *RoleMapper {
return &RoleMapper{
defaultRoleARN: iamInstance.RoleARN(defaultRole),
iamRoleKey: roleKey,
namespaceKey: namespaceKey,
namespaceRestriction: namespaceRestriction,
iam: iamInstance,
store: kubeStore,
namespaceRestrictionFormat: namespaceRestrictionFormat,
}
}
Loading

0 comments on commit d531045

Please sign in to comment.