Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Data Source: azurerm_storage_account_sas #1011

Merged
merged 15 commits into from May 20, 2018
Merged

Conversation

jzampieron
Copy link
Contributor

@jzampieron jzampieron commented Mar 20, 2018

This PR is a WIP support for programmatically generating Shared Access Signatures for Storage Accounts.

The signature computation and url query string generation from the connection strings generated by terraform azurerm_storage_account resources seem to be working.

Much additional validation and checking logic and more test cases are necessary.

(fixes #59)

@jzampieron
Copy link
Contributor Author

jzampieron commented Mar 21, 2018

@tombuildsstuff This is now working all the way through as a data source. I still need to write more/better validation functions, documentation and an acceptance test or two.

I'd appreciate a quick once-over to make sure I'm still on-track. The definition now looks like:

data "azurerm_storage_account_sas" "sas_for_metrics" {
    connection_string = "${azurerm_storage_account.dcos.primary_connection_string}"
    https_only        = true
    resource_types {
        service   = true
        container = false
        object    = false
    }
    services {
        blob  = true
        queue = false
        table = false
        file  = false
    }
    start   = "2018-03-21"
    expiry  = "2020-03-21"
    permissions {
        read    = true
        write   = true
        delete  = false
        list    = false
        add     = true
        create  = true
        update  = false
        process = false
    }
}

And gathering the output is this style:

resource "local_file" "sas_output" {
    content  = "${data.azurerm_storage_account_sas.sas_for_metrics.sas}"
    filename = "${path.cwd}/outputs/sas_output.txt"
}

All the fields are required b/c they can accidentally expose something, so it makes sense to be explicit.
The input connection_string and output sas are marked sensitive b/c they contain access tokens and/or keys of sorts.

@jzampieron
Copy link
Contributor Author

@tombuildsstuff This should be now worth a review. I added better unit tests, an acceptance test and the documentation. LMK next steps. Thanks!

@tombuildsstuff
Copy link
Member

Fixes #59

Copy link
Member

@tombuildsstuff tombuildsstuff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @jzampieron

Thanks for pushing those updates - apologies for the delayed review here, I'd added comments but not hit "submit" 😞. If we can fix up the (mostly minor) issues then this otherwise LGTM :)

Thanks!

"expiry": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(same here) do we want to add some validation to ensure this is formatted correctly? We've got a method which does this for RFC3339 dates here: https://github.com/terraform-providers/terraform-provider-azurerm/blob/master/azurerm/validators.go#L13 - which can be used like so:

ValidateFunc: validateRFC3339Date,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to go the route you specify with the validation function. In my research there are some slight differences between ISO-8601 and RFC3339. MSFT specifies that these are ISO-8601 and since the signatures are based on the actual text characters, the subtle differences may result in breakage/no-working.

Given the fragile nature, by design, of the signatures, I think leaving as-is is preferable rather than constraining the input to possibly broken validation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense from my side - we can always add it in later based on feedback 👍

"start": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to add some validation to ensure this is formatted correctly? We've got a method which does this for RFC3339 dates here: https://github.com/terraform-providers/terraform-provider-azurerm/blob/master/azurerm/validators.go#L13 - which can be used like so:

ValidateFunc: validateRFC3339Date,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same notes as above.


"file": {
Type: schema.TypeBool,
Required: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think each of these properties also needs ForceNew: true on them?`

"process": {
Type: schema.TypeBool,
Required: true,
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think each of these properties also needs ForceNew: true on them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually a result of my lack of understanding of the semantics of that flag on the outer permissions list object vs the inner schema. I'll add the flag.

"object": {
Type: schema.TypeBool,
Required: true,
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think each of these properties also needs ForceNew: true on them?


## Attributes Reference

* `sas` - (Computed) The computed Account Shared Access Signature (SAS).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we remove (Computed) here? that should be implied as it's in the Attributes reference

* `services` - (Required) A set of true/false flags which define the storage account services that are granted access by this SAS.
* `start` - (Required) The starting time and date of validity of this SAS. Must be a valid ISO-8601 format time/date string.
* `expiry` - (Required) The expiration time and date of this SAS. Must be a valid ISO-8601 format time/date string.
* `permissions` - (Required) A set of true/false flags which define the granted permissions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor can we quote true and false here?


* `connection_string` - (Required) The connection string for the storage account to which this SAS applies. Typically directly from the `primary_connection_string` attribute of a terraform created `azurerm_storage_account` resource.
* `https_only` - (Optional) Only permit `https` access. If `false`, both `http` and `https` are permitted. (Default `true`)
* `resouce_types` - (Required) A set of true/false flags which define the storage account resource types that are granted access by this SAS.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor can we quote true and false here?

* `connection_string` - (Required) The connection string for the storage account to which this SAS applies. Typically directly from the `primary_connection_string` attribute of a terraform created `azurerm_storage_account` resource.
* `https_only` - (Optional) Only permit `https` access. If `false`, both `http` and `https` are permitted. (Default `true`)
* `resouce_types` - (Required) A set of true/false flags which define the storage account resource types that are granted access by this SAS.
* `services` - (Required) A set of true/false flags which define the storage account services that are granted access by this SAS.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor can we quote true and false here?

## Argument Reference

* `connection_string` - (Required) The connection string for the storage account to which this SAS applies. Typically directly from the `primary_connection_string` attribute of a terraform created `azurerm_storage_account` resource.
* `https_only` - (Optional) Only permit `https` access. If `false`, both `http` and `https` are permitted. (Default `true`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we update "(Default true)" -> "Defaults to true" for consistency

MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"service": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to default all of these (the resource_types, permissions, and services parameters) to false and make them optional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tombuildsstuff Agree with all of the above and will incorporate those changes.
@phekmat I debated that myself and came to the conclusion to be explicitly verbose here since there are security vs function issues here.

If we default all to false, then there's an implicit no-access (all broken) case.

IMHO it's better here to be verbose and demand that folks specify exactly what they want...

This avoids an oops by granting too much access and an oops by granting no access both of which, IMHO, are a worse UX than some extra typing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IHMO it's better here to be verbose and demand that folks specify exactly what they want...

I'd agree with this approach for the moment - we can always change it later 👍

Copy link
Contributor Author

@jzampieron jzampieron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latest commit should incorporate the minor items. A few things still under discussion.

@tombuildsstuff tombuildsstuff changed the title Implement #59 New Data Source: azurerm_storage_account_sas Apr 23, 2018
@jzampieron
Copy link
Contributor Author

@tombuildsstuff Any further improvements required here? Thanks.

@tombuildsstuff
Copy link
Member

@jzampieron sorry, I started a review but didn't hit submit - I'll take another look now!

@jzampieron
Copy link
Contributor Author

@tombuildsstuff Checking in. I don't see any other actions required. Should be good to merge.

@tombuildsstuff
Copy link
Member

@jzampieron apologies for the delayed response here - I started this review then got distracted, I'll post that shortly and re-review this next week.

Chatting with Microsoft last week I discovered there's a couple of endpoints which provide this information - List Account SAS and List Storage SAS - from what I can see it appears the List Account SAS endpoint would allow us to be consistent by leaning on Azure here instead; what do you think about switching over to use that?

Thanks!

Copy link
Member

@tombuildsstuff tombuildsstuff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👋 hey @jzampieron

Apologies for the delayed review here - as mentioned below I'd started this review but not hit "submit" 😞

* `services` - (Required) A set of `true`/`false` flags which define the storage account services that are granted access by this SAS.
* `start` - (Required) The starting time and date of validity of this SAS. Must be a valid ISO-8601 format time/date string.
* `expiry` - (Required) The expiration time and date of this SAS. Must be a valid ISO-8601 format time/date string.
* `permissions` - (Required) A set of `true`/`false` flags which define the granted permissions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we update this to explicitly list the permissions, e.g.:

* `permissions` - (Required) A `permissions` block as defined below.

---

A `permissions` block contains:

* `read` - (Required) Should Read permissions be enabled for this SAS?
* `write` - (Required) Should Write permissions be enabled for this SAS?
* `delete` - (Required) Should Delete permissions be enabled for this SAS?
* `list` - (Required) Should List permissions be enabled for this SAS?
* `add` - (Required) Should Add permissions be enabled for this SAS?
* `create` - (Required) Should Create permissions be enabled for this SAS?
* `update` - (Required) Should Update permissions be enabled for this SAS?
* `process` - (Required) Should Process permissions be enabled for this SAS?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"service": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IHMO it's better here to be verbose and demand that folks specify exactly what they want...

I'd agree with this approach for the moment - we can always change it later 👍

if httpsOnly {
signedProtocol = "https"
}
signedIp := ""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 works for me

func validateArmStorageAccountSasResourceTypes(v interface{}, _ string) (ws []string, es []error) {
input := v.(string)

if !regexp.MustCompile(`\A([cos]{1,3})\z`).MatchString(input) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

given we're passing in Booleans above, I don't think this is ever possible with this resource - as such I think we can remove this for the moment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* `connection_string` - (Required) The connection string for the storage account to which this SAS applies. Typically directly from the `primary_connection_string` attribute of a terraform created `azurerm_storage_account` resource.
* `https_only` - (Optional) Only permit `https` access. If `false`, both `http` and `https` are permitted. Defaults to `true`.
* `resouce_types` - (Required) A set of `true`/`false` flags which define the storage account resource types that are granted access by this SAS.
* `services` - (Required) A set of `true`/`false` flags which define the storage account services that are granted access by this SAS.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we define these (example below)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


* `connection_string` - (Required) The connection string for the storage account to which this SAS applies. Typically directly from the `primary_connection_string` attribute of a terraform created `azurerm_storage_account` resource.
* `https_only` - (Optional) Only permit `https` access. If `false`, both `http` and `https` are permitted. Defaults to `true`.
* `resouce_types` - (Required) A set of `true`/`false` flags which define the storage account resource types that are granted access by this SAS.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we define these (example below)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

},
},

"sas": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@jzampieron
Copy link
Contributor Author

I'll work through the review in detail as above. w.r.t. the larger question of generating vs using the API.

Short term I think we should just go with this to have an answer to the immediate feature needs.

Longer term moving to the API will shift some of the burden to MSFT for compatibility, although it shouldn't really matter either way since the generation algorithm really shouldn't change at this point.

Update documentation with more verbose field details.
Copy link
Collaborator

@katbyte katbyte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jzampieron,

Thank you for this new data source. it LGTM and the tests pass:
screen shot 2018-05-19 at 20 05 46

@katbyte katbyte added this to the 1.6.0 milestone May 20, 2018
@katbyte katbyte merged commit 20514b2 into hashicorp:master May 20, 2018
katbyte added a commit that referenced this pull request May 20, 2018
@jzampieron jzampieron deleted the fix-59 branch May 21, 2018 15:17
@ghost
Copy link

ghost commented Mar 31, 2020

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. If you feel I made an error 🤖 🙉 , please reach out to my human friends 👉 hashibot-feedback@hashicorp.com. Thanks!

@hashicorp hashicorp locked and limited conversation to collaborators Mar 31, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature Request: support for Shared Access Signatures on Storage Objects [AzureRM]
4 participants