Skip to content

Commit

Permalink
Support authentication via instance principals (oracle#155)
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Lord committed Apr 10, 2018
1 parent 563024f commit 5ee73c8
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 11 deletions.
9 changes: 9 additions & 0 deletions manifests/cloud-provider-example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ auth:
passphrase: supersecretpassword
fingerprint: 8c:bf:17:7b:5f:e0:7d:13:75:11:d6:39:0d:e2:84:74

# Omit all of the above options then set useInstancePrincipals to true if you
# want to use Instance Principals API access
# (https://docs.us-phoenix-1.oraclecloud.com/Content/Identity/Tasks/callingservicesfrominstances.htm).
# Ensure you have setup the following OCI policies and your kubernetes nodes are running within them
# allow dynamic-group [your dynamic group name] to read instance-family in compartment [your compartment name]
# allow dynamic-group [your dynamic group name] to use virtual-network-family in compartment [your compartment name]
# allow dynamic-group [your dynamic group name] to manage load-balancers in compartment [your compartment name]
useInstancePrincipals: false

# compartment configures Compartment within which the cluster resides.
compartment: ocid1.compartment.oc1..aaaaaaaa3um2atybwhder4qttfhgon4j3hcxgmsvnyvx4flfjyewkkwfzwnq

Expand Down
35 changes: 27 additions & 8 deletions pkg/oci/ccm.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (

"github.com/golang/glog"
"github.com/oracle/oci-go-sdk/common"
"github.com/oracle/oci-go-sdk/common/auth"
"github.com/pkg/errors"

utilruntime "k8s.io/apimachinery/pkg/util/runtime"
Expand Down Expand Up @@ -67,14 +68,11 @@ var _ cloudprovider.Interface = &CloudProvider{}

// NewCloudProvider creates a new oci.CloudProvider.
func NewCloudProvider(config *Config) (cloudprovider.Interface, error) {
c, err := client.New(common.NewRawConfigurationProvider(
config.Auth.TenancyID,
config.Auth.UserID,
config.Auth.Region,
config.Auth.Fingerprint,
config.Auth.PrivateKey,
&config.Auth.Passphrase,
))
cp, err := buildConfigurationProvider(config)
if err != nil {
return nil, err
}
c, err := client.New(cp)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -199,3 +197,24 @@ func (cp *CloudProvider) ScrubDNS(nameservers, searches []string) (nsOut, srchOu
func (cp *CloudProvider) HasClusterID() bool {
return true
}

func buildConfigurationProvider(config *Config) (common.ConfigurationProvider, error) {
if config.Auth.UseInstancePrincipals {
glog.V(2).Info("Using instance principals configuration provider")
cp, err := auth.InstancePrincipalConfigurationProvider()
if err != nil {
return nil, errors.Wrap(err, "InstancePrincipalConfigurationProvider")
}
return cp, nil
}
glog.V(2).Info("Using raw configuration provider")
cp := common.NewRawConfigurationProvider(
config.Auth.TenancyID,
config.Auth.UserID,
config.Auth.Region,
config.Auth.Fingerprint,
config.Auth.PrivateKey,
&config.Auth.Passphrase,
)
return cp, nil
}
5 changes: 3 additions & 2 deletions pkg/oci/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import (
// AuthConfig holds the configuration required for communicating with the OCI
// API.
type AuthConfig struct {
Region string `yaml:"region"`
TenancyID string `yaml:"tenancy"`
UseInstancePrincipals bool `yaml:"useInstancePrincipals"`
Region string `yaml:"region"`
TenancyID string `yaml:"tenancy"`
// CompartmentID is DEPRECIATED and should be set on the top level Config
// struct.
CompartmentID string `yaml:"compartment"`
Expand Down
19 changes: 19 additions & 0 deletions pkg/oci/config_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,25 @@ func validateAuthConfig(c *AuthConfig, fldPath *field.Path) field.ErrorList {
if c == nil {
return append(allErrs, field.Required(fldPath, ""))
}
if c.UseInstancePrincipals {
if c.Region != "" {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("region"), "cannot be used when useInstancePrincipals is enabled"))
}
if c.TenancyID != "" {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("tenancy"), "cannot be used when useInstancePrincipals is enabled"))
}
if c.UserID != "" {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("user"), "cannot be used when useInstancePrincipals is enabled"))
}
if c.PrivateKey != "" {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("key"), "cannot be used when useInstancePrincipals is enabled"))
}
if c.Fingerprint != "" {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("fingerprint"), "cannot be used when useInstancePrincipals is enabled"))
}

return allErrs
}
if c.Region == "" {
allErrs = append(allErrs, field.Required(fldPath.Child("region"), ""))
}
Expand Down
38 changes: 37 additions & 1 deletion pkg/oci/config_validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,42 @@ func TestValidateConfig(t *testing.T) {
},
},
errs: field.ErrorList{},
},
{
name: "valid with instance principals enabled",
in: &Config{
Auth: AuthConfig{
UseInstancePrincipals: true,
},
LoadBalancer: LoadBalancerConfig{
Subnet1: "ocid1.tenancy.oc1..aaaaaaaatyn7scrtwtqedvgrxgr2xunzeo6uanvyhzxqblctwkrpisvke4kq",
Subnet2: "ocid1.subnet.oc1.phx.aaaaaaaahuxrgvs65iwdz7ekwgg3l5gyah7ww5klkwjcso74u3e4i64hvtvq",
},
},
errs: field.ErrorList{},
}, {
name: "mixing instance principals with other auth flags",
in: &Config{
Auth: AuthConfig{
UseInstancePrincipals: true,
Region: "us-phoenix-1",
TenancyID: "ocid1.tenancy.oc1..aaaaaaaatyn7scrtwtqedvgrxgr2xunzeo6uanvyhzxqblctwkrpisvke4kq",
UserID: "ocid1.user.oc1..aaaaaaaai77mql2xerv7cn6wu3nhxang3y4jk56vo5bn5l5lysl34avnui3q",
PrivateKey: "-----BEGIN RSA PRIVATE KEY----- (etc)",
Fingerprint: "8c:bf:17:7b:5f:e0:7d:13:75:11:d6:39:0d:e2:84:74",
},
LoadBalancer: LoadBalancerConfig{
Subnet1: "ocid1.tenancy.oc1..aaaaaaaatyn7scrtwtqedvgrxgr2xunzeo6uanvyhzxqblctwkrpisvke4kq",
Subnet2: "ocid1.subnet.oc1.phx.aaaaaaaahuxrgvs65iwdz7ekwgg3l5gyah7ww5klkwjcso74u3e4i64hvtvq",
},
},
errs: field.ErrorList{
&field.Error{Type: field.ErrorTypeForbidden, Field: "auth.region", Detail: "cannot be used when useInstancePrincipals is enabled", BadValue: ""},
&field.Error{Type: field.ErrorTypeForbidden, Field: "auth.tenancy", Detail: "cannot be used when useInstancePrincipals is enabled", BadValue: ""},
&field.Error{Type: field.ErrorTypeForbidden, Field: "auth.user", Detail: "cannot be used when useInstancePrincipals is enabled", BadValue: ""},
&field.Error{Type: field.ErrorTypeForbidden, Field: "auth.key", Detail: "cannot be used when useInstancePrincipals is enabled", BadValue: ""},
&field.Error{Type: field.ErrorTypeForbidden, Field: "auth.fingerprint", Detail: "cannot be used when useInstancePrincipals is enabled", BadValue: ""},
},
}, {
name: "missing_region",
in: &Config{
Expand Down Expand Up @@ -193,7 +229,7 @@ func TestValidateConfig(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
result := ValidateConfig(tt.in)
if !reflect.DeepEqual(result, tt.errs) {
t.Errorf("ValidateConfig(%#v)\n=> %#v\nExpected: %#v", tt.in, result, tt.errs)
t.Errorf("ValidateConfig(%#v)\n=> %v\nExpected: %v", tt.in, result, tt.errs)
}
})
}
Expand Down

0 comments on commit 5ee73c8

Please sign in to comment.