-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New Resource:
azurerm_azuread_service_principal_password
Tests pass: ``` $ acctests azurerm TestAccAzureRMActiveDirectoryServicePrincipalPassword_ === RUN TestAccAzureRMActiveDirectoryServicePrincipalPassword_basic --- PASS: TestAccAzureRMActiveDirectoryServicePrincipalPassword_basic (36.08s) === RUN TestAccAzureRMActiveDirectoryServicePrincipalPassword_customKeyId --- PASS: TestAccAzureRMActiveDirectoryServicePrincipalPassword_customKeyId (26.22s) PASS ok github.com/terraform-providers/terraform-provider-azurerm/azurerm 62.335s ```
- Loading branch information
1 parent
cb94176
commit 0e8c24e
Showing
11 changed files
with
533 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package validate | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/hashicorp/go-uuid" | ||
) | ||
|
||
func UUID(i interface{}, k string) (_ []string, errors []error) { | ||
v, ok := i.(string) | ||
if !ok { | ||
errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) | ||
return | ||
} | ||
|
||
if _, err := uuid.ParseUUID(v); err != nil { | ||
errors = append(errors, fmt.Errorf("%q isn't a valid UUID (%q): %+v", k, v, err)) | ||
} | ||
|
||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package validate | ||
|
||
import "testing" | ||
|
||
func TestUUID(t *testing.T) { | ||
cases := []struct { | ||
Input string | ||
Errors int | ||
}{ | ||
{ | ||
Input: "", | ||
Errors: 1, | ||
}, | ||
{ | ||
Input: "hello-world", | ||
Errors: 1, | ||
}, | ||
{ | ||
Input: "00000000-0000-111-0000-000000000000", | ||
Errors: 1, | ||
}, | ||
{ | ||
Input: "00000000-0000-0000-0000-000000000000", | ||
Errors: 0, | ||
}, | ||
} | ||
|
||
for _, tc := range cases { | ||
t.Run(tc.Input, func(t *testing.T) { | ||
_, errors := UUID(tc.Input, "test") | ||
|
||
if len(errors) != tc.Errors { | ||
t.Fatalf("Expected UUID to have %d not %d errors for %q", tc.Errors, len(errors), tc.Input) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
241 changes: 241 additions & 0 deletions
241
azurerm/resource_arm_azuread_service_principal_password.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
package azurerm | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"strings" | ||
"time" | ||
|
||
"github.com/Azure/azure-sdk-for-go/services/graphrbac/1.6/graphrbac" | ||
"github.com/Azure/go-autorest/autorest/date" | ||
"github.com/hashicorp/go-uuid" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" | ||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" | ||
) | ||
|
||
func resourceArmActiveDirectoryServicePrincipalPassword() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceArmActiveDirectoryServicePrincipalPasswordCreate, | ||
Read: resourceArmActiveDirectoryServicePrincipalPasswordRead, | ||
Delete: resourceArmActiveDirectoryServicePrincipalPasswordDelete, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"service_principal_id": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: validate.UUID, | ||
}, | ||
|
||
"key_id": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Computed: true, | ||
ForceNew: true, | ||
ValidateFunc: validate.UUID, | ||
}, | ||
|
||
"value": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
Sensitive: true, | ||
}, | ||
|
||
"start_date": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Computed: true, | ||
ForceNew: true, | ||
ValidateFunc: validate.RFC3339Time, | ||
}, | ||
|
||
"end_date": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: validate.RFC3339Time, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceArmActiveDirectoryServicePrincipalPasswordCreate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*ArmClient).servicePrincipalsClient | ||
ctx := meta.(*ArmClient).StopContext | ||
|
||
objectId := d.Get("service_principal_id").(string) | ||
value := d.Get("value").(string) | ||
// errors will be handled by the validation | ||
endDate, _ := time.Parse(time.RFC3339, d.Get("end_date").(string)) | ||
|
||
var keyId string | ||
if v, ok := d.GetOk("key_id"); ok { | ||
keyId = v.(string) | ||
} else { | ||
kid, err := uuid.GenerateUUID() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
keyId = kid | ||
} | ||
|
||
credential := graphrbac.PasswordCredential{ | ||
KeyID: utils.String(keyId), | ||
Value: utils.String(value), | ||
EndDate: &date.Time{Time: endDate}, | ||
} | ||
|
||
if v, ok := d.GetOk("start_date"); ok { | ||
// errors will be handled by the validation | ||
startDate, _ := time.Parse(time.RFC3339, v.(string)) | ||
credential.StartDate = &date.Time{Time: startDate} | ||
} | ||
|
||
azureRMLockByName(objectId, servicePrincipalResourceName) | ||
defer azureRMUnlockByName(objectId, servicePrincipalResourceName) | ||
|
||
existingCredentials, err := client.ListPasswordCredentials(ctx, objectId) | ||
if err != nil { | ||
return fmt.Errorf("Error Listing Password Credentials for Service Principal %q: %+v", objectId, err) | ||
} | ||
|
||
updatedCredentials := make([]graphrbac.PasswordCredential, 0) | ||
if existingCredentials.Value != nil { | ||
updatedCredentials = *existingCredentials.Value | ||
} | ||
|
||
updatedCredentials = append(updatedCredentials, credential) | ||
|
||
parameters := graphrbac.PasswordCredentialsUpdateParameters{ | ||
Value: &updatedCredentials, | ||
} | ||
_, err = client.UpdatePasswordCredentials(ctx, objectId, parameters) | ||
if err != nil { | ||
return fmt.Errorf("Error creating Password Credential %q for Service Principal %q: %+v", keyId, objectId, err) | ||
} | ||
|
||
d.SetId(fmt.Sprintf("%s/%s", objectId, keyId)) | ||
|
||
return resourceArmActiveDirectoryServicePrincipalPasswordRead(d, meta) | ||
} | ||
|
||
func resourceArmActiveDirectoryServicePrincipalPasswordRead(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*ArmClient).servicePrincipalsClient | ||
ctx := meta.(*ArmClient).StopContext | ||
|
||
id := strings.Split(d.Id(), "/") | ||
if len(id) != 2 { | ||
return fmt.Errorf("ID should be in the format {objectId}/{keyId} - but got %q", d.Id()) | ||
} | ||
|
||
objectId := id[0] | ||
keyId := id[1] | ||
|
||
// ensure the parent Service Principal exists | ||
servicePrincipal, err := client.Get(ctx, objectId) | ||
if err != nil { | ||
// the parent Service Principal has been removed - skip it | ||
if utils.ResponseWasNotFound(servicePrincipal.Response) { | ||
log.Printf("[DEBUG] Service Principal with Object ID %q was not found - removing from state!", objectId) | ||
d.SetId("") | ||
return nil | ||
} | ||
return fmt.Errorf("Error retrieving Service Principal ID %q: %+v", objectId, err) | ||
} | ||
|
||
credentials, err := client.ListPasswordCredentials(ctx, objectId) | ||
if err != nil { | ||
return fmt.Errorf("Error Listing Password Credentials for Service Principal with Object ID %q: %+v", objectId, err) | ||
} | ||
|
||
var credential *graphrbac.PasswordCredential | ||
for _, c := range *credentials.Value { | ||
if c.KeyID == nil { | ||
continue | ||
} | ||
|
||
if *c.KeyID == keyId { | ||
credential = &c | ||
break | ||
} | ||
} | ||
|
||
if credential == nil { | ||
log.Printf("[DEBUG] Service Principal Password %q (Object ID %q) was not found - removing from state!", keyId, objectId) | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
// value is available in the SDK but isn't returned from the API | ||
d.Set("key_id", credential.KeyID) | ||
d.Set("service_principal_id", objectId) | ||
|
||
if endDate := credential.EndDate; endDate != nil { | ||
d.Set("end_date", endDate.Format(time.RFC3339)) | ||
} | ||
|
||
if startDate := credential.StartDate; startDate != nil { | ||
d.Set("start_date", startDate.Format(time.RFC3339)) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceArmActiveDirectoryServicePrincipalPasswordDelete(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*ArmClient).servicePrincipalsClient | ||
ctx := meta.(*ArmClient).StopContext | ||
|
||
id := strings.Split(d.Id(), "/") | ||
if len(id) != 2 { | ||
return fmt.Errorf("ID should be in the format {objectId}/{keyId} - but got %q", d.Id()) | ||
} | ||
|
||
objectId := id[0] | ||
keyId := id[1] | ||
|
||
azureRMLockByName(objectId, servicePrincipalResourceName) | ||
defer azureRMUnlockByName(objectId, servicePrincipalResourceName) | ||
|
||
// ensure the parent Service Principal exists | ||
servicePrincipal, err := client.Get(ctx, objectId) | ||
if err != nil { | ||
// the parent Service Principal was removed - skip it | ||
if utils.ResponseWasNotFound(servicePrincipal.Response) { | ||
return nil | ||
} | ||
|
||
return fmt.Errorf("Error retrieving Service Principal ID %q: %+v", objectId, err) | ||
} | ||
|
||
existing, err := client.ListPasswordCredentials(ctx, objectId) | ||
if err != nil { | ||
return fmt.Errorf("Error Listing Password Credentials for Service Principal with Object ID %q: %+v", objectId, err) | ||
} | ||
|
||
updatedCredentials := make([]graphrbac.PasswordCredential, 0) | ||
for _, credential := range *existing.Value { | ||
if credential.KeyID == nil { | ||
continue | ||
} | ||
|
||
if *credential.KeyID != keyId { | ||
updatedCredentials = append(updatedCredentials, credential) | ||
} | ||
} | ||
|
||
parameters := graphrbac.PasswordCredentialsUpdateParameters{ | ||
Value: &updatedCredentials, | ||
} | ||
_, err = client.UpdatePasswordCredentials(ctx, objectId, parameters) | ||
if err != nil { | ||
return fmt.Errorf("Error removing Password %q from Service Principal %q: %+v", keyId, objectId, err) | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.