Skip to content

Commit

Permalink
feat: adds assume role capability to switch provider context (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
becelot authored Aug 24, 2023
1 parent 7138a14 commit 77b47d0
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 0 deletions.
27 changes: 27 additions & 0 deletions cancom/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package cancom

import (
"context"
"fmt"

"github.com/cancom/terraform-provider-cancom/client"
client_iam "github.com/cancom/terraform-provider-cancom/client/services/iam"
client_serviceregistry "github.com/cancom/terraform-provider-cancom/client/services/service-registry"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand All @@ -29,6 +31,11 @@ func Provider() *schema.Provider {
Description: "Service Registry to use for endpoint discovery",
DefaultFunc: schema.EnvDefaultFunc("CANCOM_SERVICE_REGISTRY", "https://service-registry.portal.cancom.io"),
},
"role": {
Type: schema.TypeString,
Optional: true,
Description: "Role to assume with the provided token. Resources are created with this role instead of the original principal",
},
},
ResourcesMap: ar,
DataSourcesMap: map[string]*schema.Resource{},
Expand All @@ -39,6 +46,7 @@ func Provider() *schema.Provider {
func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
token := d.Get("token").(string)
service_registry := d.Get("service_registry").(string)
role := d.Get("role").(string)

// Warning or errors can be collected in a slice type
var diags diag.Diagnostics
Expand Down Expand Up @@ -68,6 +76,25 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{}
c.ServiceURLs[service.ServiceName] = service.ServiceEndpoint.Backend
}

if role != "" {
c.HostURL = c.ServiceURLs["iam"]

token, err := (*client_iam.Client)(c).AssumeRole(&client_iam.AssumeRoleRequest{
Role: role,
})

if err != nil {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: fmt.Sprintf("Could not assume role %s", role),
Detail: err.Error(),
})
return nil, diags
}

c.Token = token.Jwt
}

return c, diags
}

Expand Down
27 changes: 27 additions & 0 deletions client/services/iam/iam.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,30 @@ func (c *Client) RemovePolicyFromUser(PolicyRequest *PolicyRequest, principal st

return nil
}

func (c *Client) AssumeRole(role *AssumeRoleRequest) (*AssumeRoleResponse, error) {
body, err := json.Marshal(role)

if err != nil {
return nil, err
}

req, err := http.NewRequest("POST", fmt.Sprintf("%s/v1/AssumeRole", c.HostURL), bytes.NewBuffer(body))

if err != nil {
return nil, err
}

resp, err := (*client.Client)(c).DoRequest(req)
if err != nil {
return nil, err
}

assumeRole := AssumeRoleResponse{}
err = json.Unmarshal(resp, &assumeRole)
if err != nil {
return nil, err
}

return &assumeRole, nil
}
9 changes: 9 additions & 0 deletions client/services/iam/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,12 @@ type Role struct {
Group string `json:"group"`
CreatedBy string `json:"createdBy"`
}

type AssumeRoleRequest struct {
Role string `json:"role"`
}

type AssumeRoleResponse struct {
Jwt string `json:"jwt"`
Message string `json:"message"`
}
12 changes: 12 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,22 @@ $ export CANCOM_TOKEN="insertyourcancomtokenhere"
$ terraform plan
```

### Context

By default, the terraform is executed in the context of the current principle identified by the token. If you need to change context, you can also provide the `role` parameter to assume a role in a different tenant. In this case, all actions are executed within the context of the assumed role.

```terraform
provider "cancom" {
token = "<token>"
role = "crn:123456789012::iam:role:TerraFormRole"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Optional

- `role` (String) Role to assume with the provided token. Resources are created with this role instead of the original principal
- `service_registry` (String) Service Registry to use for endpoint discovery
- `token` (String) API Token retrieved from [https://portal.cancom.io](https://portal.cancom.io)
4 changes: 4 additions & 0 deletions examples/provider_role.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
provider "cancom" {
token = "<token>"
role = "crn:123456789012::iam:role:TerraFormRole"
}
6 changes: 6 additions & 0 deletions templates/index.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,10 @@ Usage:

{{ codefile "sh" "examples/index-env-var-tf-plan.txt" }}

### Context

By default, the terraform is executed in the context of the current principle identified by the token. If you need to change context, you can also provide the `role` parameter to assume a role in a different tenant. In this case, all actions are executed within the context of the assumed role.

{{ tffile "examples/provider_role.tf" }}

{{ .SchemaMarkdown | trimspace }}

0 comments on commit 77b47d0

Please sign in to comment.