Skip to content

Commit b4dbb09

Browse files
committed
validate supplied auth variables when OCI_AUTH is set to InstancePrincipal or InstancePrincipalWithCerts
1 parent 512d845 commit b4dbb09

File tree

3 files changed

+159
-67
lines changed

3 files changed

+159
-67
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
### Fixed
99
- Retried SDK calls are now jittered to avoid herding of retry requests in high parallelism scenarios
10+
- Fail the initialization of the provider if either of `user_ocid`, `fingerprint`, `private_key`, `private_key_path` or `private_key_password` are specified for `InstancePrincipal` or `InstancePrincipalWithCerts` auth mode.
1011

1112
## 3.11.2 (January 10, 2019)
1213

oci/provider.go

Lines changed: 112 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
)
2626

2727
var descriptions map[string]string
28+
var apiKeyConfigAttributes = [...]string{userOcidAttrName, fingerprintAttrName, privateKeyAttrName, privateKeyPathAttrName, privateKeyPasswordAttrName}
2829

2930
const (
3031
authAPIKeySetting = "ApiKey"
@@ -42,6 +43,21 @@ const (
4243
customCertLocationEnv = "custom_cert_location"
4344
oracleR1DomainNameEnv = "oracle_r1_domain_name" // deprecate
4445
r1CertLocationEnv = "R1_CERT_LOCATION" // deprecate
46+
47+
authAttrName = "auth"
48+
tenancyOcidAttrName = "tenancy_ocid"
49+
userOcidAttrName = "user_ocid"
50+
fingerprintAttrName = "fingerprint"
51+
privateKeyAttrName = "private_key"
52+
privateKeyPathAttrName = "private_key_path"
53+
privateKeyPasswordAttrName = "private_key_password"
54+
regionAttrName = "region"
55+
disableAutoRetriesAttrName = "disable_auto_retries"
56+
retryDurationSecondsAttrName = "retry_duration_seconds"
57+
oboTokenAttrName = "obo_token"
58+
59+
tfEnvPrefix = "TF_VAR_"
60+
ociEnvPrefix = "OCI_"
4561
)
4662

4763
// OboTokenProvider interface that wraps information about auth tokens so the sdk client can make calls
@@ -61,24 +77,32 @@ func (provider emptyOboTokenProvider) OboToken() (string, error) {
6177
type oboTokenProviderFromEnv struct{}
6278

6379
func (p oboTokenProviderFromEnv) OboToken() (string, error) {
64-
return getEnvSettingWithBlankDefault("obo_token"), nil
80+
return getEnvSettingWithBlankDefault(oboTokenAttrName), nil
81+
}
82+
83+
func tfVarName(attrName string) string {
84+
return tfEnvPrefix + attrName
85+
}
86+
87+
func ociVarName(attrName string) string {
88+
return ociEnvPrefix + strings.ToUpper(attrName)
6589
}
6690

6791
func init() {
6892
descriptions = map[string]string{
69-
"auth": fmt.Sprintf("(Optional) The type of auth to use. Options are '%s' and '%s'. By default, '%s' will be used.", authAPIKeySetting, authInstancePrincipalSetting, authAPIKeySetting),
70-
"tenancy_ocid": fmt.Sprintf("(Optional) The tenancy OCID for a user. The tenancy OCID can be found at the bottom of user settings in the Oracle Cloud Infrastructure console. Required if auth is set to '%s', ignored otherwise.", authAPIKeySetting),
71-
"user_ocid": fmt.Sprintf("(Optional) The user OCID. This can be found in user settings in the Oracle Cloud Infrastructure console. Required if auth is set to '%s', ignored otherwise.", authAPIKeySetting),
72-
"fingerprint": fmt.Sprintf("(Optional) The fingerprint for the user's RSA key. This can be found in user settings in the Oracle Cloud Infrastructure console. Required if auth is set to '%s', ignored otherwise.", authAPIKeySetting),
73-
"region": "(Required) The region for API connections (e.g. us-ashburn-1).",
74-
"private_key": "(Optional) A PEM formatted RSA private key for the user.\n" +
93+
authAttrName: fmt.Sprintf("(Optional) The type of auth to use. Options are '%s' and '%s'. By default, '%s' will be used.", authAPIKeySetting, authInstancePrincipalSetting, authAPIKeySetting),
94+
tenancyOcidAttrName: fmt.Sprintf("(Optional) The tenancy OCID for a user. The tenancy OCID can be found at the bottom of user settings in the Oracle Cloud Infrastructure console. Required if auth is set to '%s', ignored otherwise.", authAPIKeySetting),
95+
userOcidAttrName: fmt.Sprintf("(Optional) The user OCID. This can be found in user settings in the Oracle Cloud Infrastructure console. Required if auth is set to '%s', ignored otherwise.", authAPIKeySetting),
96+
fingerprintAttrName: fmt.Sprintf("(Optional) The fingerprint for the user's RSA key. This can be found in user settings in the Oracle Cloud Infrastructure console. Required if auth is set to '%s', ignored otherwise.", authAPIKeySetting),
97+
regionAttrName: "(Required) The region for API connections (e.g. us-ashburn-1).",
98+
privateKeyAttrName: "(Optional) A PEM formatted RSA private key for the user.\n" +
7599
fmt.Sprintf("A private_key or a private_key_path must be provided if auth is set to '%s', ignored otherwise.", authAPIKeySetting),
76-
"private_key_path": "(Optional) The path to the user's PEM formatted private key.\n" +
100+
privateKeyPathAttrName: "(Optional) The path to the user's PEM formatted private key.\n" +
77101
fmt.Sprintf("A private_key or a private_key_path must be provided if auth is set to '%s', ignored otherwise.", authAPIKeySetting),
78-
"private_key_password": "(Optional) The password used to secure the private key.",
79-
"disable_auto_retries": "(Optional) Disable automatic retries for retriable errors.\n" +
102+
privateKeyPasswordAttrName: "(Optional) The password used to secure the private key.",
103+
disableAutoRetriesAttrName: "(Optional) Disable automatic retries for retriable errors.\n" +
80104
"Automatic retries were introduced to solve some eventual consistency problems but it also introduced performance issues on destroy operations.",
81-
"retry_duration_seconds": "(Optional) The minimum duration (in seconds) to retry a resource operation in response to an error.\n" +
105+
retryDurationSecondsAttrName: "(Optional) The minimum duration (in seconds) to retry a resource operation in response to an error.\n" +
82106
"The actual retry duration may be longer due to jittering of retry operations. This value is ignored if the `disable_auto_retries` field is set to true.",
83107
}
84108
}
@@ -95,73 +119,73 @@ func Provider(configfn schema.ConfigureFunc) terraform.ResourceProvider {
95119

96120
func schemaMap() map[string]*schema.Schema {
97121
return map[string]*schema.Schema{
98-
"auth": {
122+
authAttrName: {
99123
Type: schema.TypeString,
100124
Optional: true,
101-
Description: descriptions["auth"],
102-
DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TF_VAR_auth", "OCI_AUTH"}, authAPIKeySetting),
125+
Description: descriptions[authAttrName],
126+
DefaultFunc: schema.MultiEnvDefaultFunc([]string{tfVarName(authAttrName), ociVarName(authAttrName)}, authAPIKeySetting),
103127
ValidateFunc: validation.StringInSlice([]string{authAPIKeySetting, authInstancePrincipalSetting, authInstancePrincipalWithCertsSetting}, true),
104128
},
105-
"tenancy_ocid": {
129+
tenancyOcidAttrName: {
106130
Type: schema.TypeString,
107131
Optional: true,
108-
Description: descriptions["tenancy_ocid"],
109-
DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TF_VAR_tenancy_ocid", "OCI_TENANCY_OCID"}, nil),
132+
Description: descriptions[tenancyOcidAttrName],
133+
DefaultFunc: schema.MultiEnvDefaultFunc([]string{tfVarName(tenancyOcidAttrName), ociVarName(tenancyOcidAttrName)}, nil),
110134
},
111-
"user_ocid": {
135+
userOcidAttrName: {
112136
Type: schema.TypeString,
113137
Optional: true,
114-
Description: descriptions["user_ocid"],
115-
DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TF_VAR_user_ocid", "OCI_USER_OCID"}, nil),
138+
Description: descriptions[userOcidAttrName],
139+
DefaultFunc: schema.MultiEnvDefaultFunc([]string{tfVarName(userOcidAttrName), ociVarName(userOcidAttrName)}, nil),
116140
},
117-
"fingerprint": {
141+
fingerprintAttrName: {
118142
Type: schema.TypeString,
119143
Optional: true,
120-
Description: descriptions["fingerprint"],
121-
DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TF_VAR_fingerprint", "OCI_FINGERPRINT"}, nil),
144+
Description: descriptions[fingerprintAttrName],
145+
DefaultFunc: schema.MultiEnvDefaultFunc([]string{tfVarName(fingerprintAttrName), ociVarName(fingerprintAttrName)}, nil),
122146
},
123147
// Mostly used for testing. Don't put keys in your .tf files
124-
"private_key": {
148+
privateKeyAttrName: {
125149
Type: schema.TypeString,
126150
Optional: true,
127151
Default: "",
128152
Sensitive: true,
129-
Description: descriptions["private_key"],
130-
DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TF_VAR_private_key", "OCI_PRIVATE_KEY"}, nil),
153+
Description: descriptions[privateKeyAttrName],
154+
DefaultFunc: schema.MultiEnvDefaultFunc([]string{tfVarName(privateKeyAttrName), ociVarName(privateKeyAttrName)}, nil),
131155
},
132-
"private_key_path": {
156+
privateKeyPathAttrName: {
133157
Type: schema.TypeString,
134158
Optional: true,
135-
Description: descriptions["private_key_path"],
136-
DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TF_VAR_private_key_path", "OCI_PRIVATE_KEY_PATH"}, nil),
159+
Description: descriptions[privateKeyPathAttrName],
160+
DefaultFunc: schema.MultiEnvDefaultFunc([]string{tfVarName(privateKeyPathAttrName), ociVarName(privateKeyPathAttrName)}, nil),
137161
},
138-
"private_key_password": {
162+
privateKeyPasswordAttrName: {
139163
Type: schema.TypeString,
140164
Optional: true,
141165
Sensitive: true,
142166
Default: "",
143-
Description: descriptions["private_key_password"],
144-
DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TF_VAR_private_key_password", "OCI_PRIVATE_KEY_PASSWORD"}, nil),
167+
Description: descriptions[privateKeyPasswordAttrName],
168+
DefaultFunc: schema.MultiEnvDefaultFunc([]string{tfVarName(privateKeyPasswordAttrName), ociVarName(privateKeyPasswordAttrName)}, nil),
145169
},
146-
"region": {
170+
regionAttrName: {
147171
Type: schema.TypeString,
148172
Required: true,
149-
Description: descriptions["region"],
150-
DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TF_VAR_region", "OCI_REGION"}, nil),
173+
Description: descriptions[regionAttrName],
174+
DefaultFunc: schema.MultiEnvDefaultFunc([]string{tfVarName(regionAttrName), ociVarName(regionAttrName)}, nil),
151175
},
152-
"disable_auto_retries": {
176+
disableAutoRetriesAttrName: {
153177
Type: schema.TypeBool,
154178
Optional: true,
155179
Default: false,
156-
Description: descriptions["disable_auto_retries"],
157-
DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TF_VAR_disable_auto_retries", "OCI_DISABLE_AUTO_RETRIES"}, nil),
180+
Description: descriptions[disableAutoRetriesAttrName],
181+
DefaultFunc: schema.MultiEnvDefaultFunc([]string{tfVarName(disableAutoRetriesAttrName), ociVarName(disableAutoRetriesAttrName)}, nil),
158182
},
159-
"retry_duration_seconds": {
183+
retryDurationSecondsAttrName: {
160184
Type: schema.TypeInt,
161185
Optional: true,
162186
Default: false,
163-
Description: descriptions["retry_duration_seconds"],
164-
DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TF_VAR_retry_duration_seconds", "OCI_RETRY_DURATION_SECONDS"}, nil),
187+
Description: descriptions[retryDurationSecondsAttrName],
188+
DefaultFunc: schema.MultiEnvDefaultFunc([]string{tfVarName(retryDurationSecondsAttrName), ociVarName(retryDurationSecondsAttrName)}, nil),
165189
},
166190
}
167191
}
@@ -456,11 +480,11 @@ func getEnvSettingWithBlankDefault(s string) string {
456480
}
457481

458482
func getEnvSettingWithDefault(s string, dv string) string {
459-
v := os.Getenv("TF_VAR_" + s)
483+
v := os.Getenv(tfEnvPrefix + s)
460484
if v != "" {
461485
return v
462486
}
463-
v = os.Getenv("OCI_" + s)
487+
v = os.Getenv(ociEnvPrefix + s)
464488
if v != "" {
465489
return v
466490
}
@@ -481,15 +505,26 @@ func getRequiredEnvSetting(s string) string {
481505
}
482506

483507
func validateConfigForAPIKeyAuth(d *schema.ResourceData) error {
484-
_, hasTenancyOCID := d.GetOkExists("tenancy_ocid")
485-
_, hasUserOCID := d.GetOkExists("user_ocid")
486-
_, hasFingerprint := d.GetOkExists("fingerprint")
508+
_, hasTenancyOCID := d.GetOkExists(tenancyOcidAttrName)
509+
_, hasUserOCID := d.GetOkExists(userOcidAttrName)
510+
_, hasFingerprint := d.GetOkExists(fingerprintAttrName)
487511
if !hasTenancyOCID || !hasUserOCID || !hasFingerprint {
488512
return fmt.Errorf("when auth is set to '%s', tenancy_ocid, user_ocid, and fingerprint are required", authAPIKeySetting)
489513
}
490514
return nil
491515
}
492516

517+
func checkIncompatibleAttrsForApiKeyAuth(d *schema.ResourceData) ([]string, bool) {
518+
var apiKeyConfigAttributesToUnset []string
519+
for _, apiKeyConfigAttribute := range apiKeyConfigAttributes {
520+
apiKeyConfigAttributeValue, hasConfigVariable := d.GetOkExists(apiKeyConfigAttribute)
521+
if (hasConfigVariable && apiKeyConfigAttributeValue != "") || getEnvSettingWithBlankDefault(apiKeyConfigAttribute) != "" {
522+
apiKeyConfigAttributesToUnset = append(apiKeyConfigAttributesToUnset, apiKeyConfigAttribute)
523+
}
524+
}
525+
return apiKeyConfigAttributesToUnset, len(apiKeyConfigAttributesToUnset) == 0
526+
}
527+
493528
func getCertificateFileBytes(certificateFileFullPath string) (pemRaw []byte, err error) {
494529
absFile, err := filepath.Abs(certificateFileFullPath)
495530
if err != nil {
@@ -505,10 +540,10 @@ func getCertificateFileBytes(certificateFileFullPath string) (pemRaw []byte, err
505540
func ProviderConfig(d *schema.ResourceData) (clients interface{}, err error) {
506541
clients = &OracleClients{configuration: map[string]string{}}
507542

508-
if d.Get("disable_auto_retries").(bool) {
543+
if d.Get(disableAutoRetriesAttrName).(bool) {
509544
shortRetryTime = 0
510545
longRetryTime = 0
511-
} else if retryDurationSeconds, exists := d.GetOkExists("retry_duration_seconds"); exists {
546+
} else if retryDurationSeconds, exists := d.GetOkExists(retryDurationSecondsAttrName); exists {
512547
val := time.Duration(retryDurationSeconds.(int)) * time.Second
513548
if retryDurationSeconds.(int) < 0 {
514549
// Retry for maximum amount of time, if a negative value was specified
@@ -517,8 +552,8 @@ func ProviderConfig(d *schema.ResourceData) (clients interface{}, err error) {
517552
configuredRetryDuration = &val
518553
}
519554

520-
auth := strings.ToLower(d.Get("auth").(string))
521-
clients.(*OracleClients).configuration["auth"] = auth
555+
auth := strings.ToLower(d.Get(authAttrName).(string))
556+
clients.(*OracleClients).configuration[authAttrName] = auth
522557

523558
userAgentProviderName := getEnvSettingWithDefault(userAgentProviderNameEnv, defaultUserAgentProviderName)
524559
userAgent := fmt.Sprintf(userAgentFormatter, oci_common.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH, terraform.VersionString(), userAgentProviderName, Version)
@@ -543,19 +578,31 @@ func ProviderConfig(d *schema.ResourceData) (clients interface{}, err error) {
543578
return nil, err
544579
}
545580
case strings.ToLower(authInstancePrincipalSetting):
546-
region, ok := d.GetOkExists("region")
581+
apiKeyConfigVariablesToUnset, ok := checkIncompatibleAttrsForApiKeyAuth(d)
582+
if !ok {
583+
return nil, fmt.Errorf(`authentication (%s) is set to "%s". To use "%s" authentication user credentials should be removed from the configuration.
584+
The values for the %v are provided now.`, ociVarName(authAttrName), authInstancePrincipalSetting, authInstancePrincipalSetting, apiKeyConfigVariablesToUnset)
585+
}
586+
587+
region, ok := d.GetOkExists(regionAttrName)
547588
if !ok {
548-
return nil, fmt.Errorf("can not get region from Terraform configuration (InstancePrincipal)")
589+
return nil, fmt.Errorf("can not get %s from Terraform configuration (InstancePrincipal)", regionAttrName)
549590
}
550591
cfg, err := oci_common_auth.InstancePrincipalConfigurationProviderForRegion(oci_common.StringToRegion(region.(string)))
551592
if err != nil {
552593
return nil, err
553594
}
554595
configProviders = append(configProviders, cfg)
555596
case strings.ToLower(authInstancePrincipalWithCertsSetting):
556-
region, ok := d.GetOkExists("region")
597+
apiKeyConfigVariablesToUnset, ok := checkIncompatibleAttrsForApiKeyAuth(d)
598+
if !ok {
599+
return nil, fmt.Errorf(`authentication (%s) is set to "%s". To use "%s" authentication user credentials should be removed from the configuration.
600+
The values for the %v are provided now.`, ociVarName(authAttrName), authInstancePrincipalWithCertsSetting, authInstancePrincipalWithCertsSetting, apiKeyConfigVariablesToUnset)
601+
}
602+
603+
region, ok := d.GetOkExists(regionAttrName)
557604
if !ok {
558-
return nil, fmt.Errorf("can not get region from Terraform configuration (InstancePrincipalWithCerts)")
605+
return nil, fmt.Errorf("can not get %s from Terraform configuration (InstancePrincipalWithCerts)", regionAttrName)
559606
}
560607

561608
defaultCertsDir, err := os.Getwd()
@@ -629,31 +676,31 @@ type ResourceDataConfigProvider struct {
629676
// The ComposingConfigurationProvider in SDK should log the errors as debug statements instead.
630677

631678
func (p ResourceDataConfigProvider) TenancyOCID() (string, error) {
632-
if tenancyOCID, ok := p.D.GetOkExists("tenancy_ocid"); ok {
679+
if tenancyOCID, ok := p.D.GetOkExists(tenancyOcidAttrName); ok {
633680
return tenancyOCID.(string), nil
634681
}
635-
return "", fmt.Errorf("can not get tenancy_ocid from Terraform configuration")
682+
return "", fmt.Errorf("can not get %s from Terraform configuration", tenancyOcidAttrName)
636683
}
637684

638685
func (p ResourceDataConfigProvider) UserOCID() (string, error) {
639-
if userOCID, ok := p.D.GetOkExists("user_ocid"); ok {
686+
if userOCID, ok := p.D.GetOkExists(userOcidAttrName); ok {
640687
return userOCID.(string), nil
641688
}
642-
return "", fmt.Errorf("can not get user_ocid from Terraform configuration")
689+
return "", fmt.Errorf("can not get %s from Terraform configuration", userOcidAttrName)
643690
}
644691

645692
func (p ResourceDataConfigProvider) KeyFingerprint() (string, error) {
646-
if fingerprint, ok := p.D.GetOkExists("fingerprint"); ok {
693+
if fingerprint, ok := p.D.GetOkExists(fingerprintAttrName); ok {
647694
return fingerprint.(string), nil
648695
}
649-
return "", fmt.Errorf("can not get fingerprint from Terraform configuration")
696+
return "", fmt.Errorf("can not get %s from Terraform configuration", fingerprintAttrName)
650697
}
651698

652699
func (p ResourceDataConfigProvider) Region() (string, error) {
653-
if region, ok := p.D.GetOkExists("region"); ok {
700+
if region, ok := p.D.GetOkExists(regionAttrName); ok {
654701
return region.(string), nil
655702
}
656-
return "", fmt.Errorf("can not get region from Terraform configuration")
703+
return "", fmt.Errorf("can not get %s from Terraform configuration", regionAttrName)
657704
}
658705

659706
func (p ResourceDataConfigProvider) KeyID() (string, error) {
@@ -677,15 +724,15 @@ func (p ResourceDataConfigProvider) KeyID() (string, error) {
677724

678725
func (p ResourceDataConfigProvider) PrivateRSAKey() (key *rsa.PrivateKey, err error) {
679726
password := ""
680-
if privateKeyPassword, hasPrivateKeyPassword := p.D.GetOkExists("private_key_password"); hasPrivateKeyPassword {
727+
if privateKeyPassword, hasPrivateKeyPassword := p.D.GetOkExists(privateKeyPasswordAttrName); hasPrivateKeyPassword {
681728
password = privateKeyPassword.(string)
682729
}
683730

684-
if privateKey, hasPrivateKey := p.D.GetOkExists("private_key"); hasPrivateKey {
731+
if privateKey, hasPrivateKey := p.D.GetOkExists(privateKeyAttrName); hasPrivateKey {
685732
return oci_common.PrivateKeyFromBytes([]byte(privateKey.(string)), &password)
686733
}
687734

688-
if privateKeyPath, hasPrivateKeyPath := p.D.GetOkExists("private_key_path"); hasPrivateKeyPath {
735+
if privateKeyPath, hasPrivateKeyPath := p.D.GetOkExists(privateKeyPathAttrName); hasPrivateKeyPath {
689736
pemFileContent, readFileErr := ioutil.ReadFile(privateKeyPath.(string))
690737
if readFileErr != nil {
691738
return nil, fmt.Errorf("Can not read private key from: '%s', Error: %q", privateKeyPath, readFileErr)

0 commit comments

Comments
 (0)