Compare commits

...
6 Commits
Author SHA1 Message Date
Danielle Miu b7eadd565f update changelog to include policies feat
Lint GitHub Actions workflows / actionlint (push) Failing after 13s
make-gen-delta / Check for uncommitted changes from make gen (push) Failing after 1m5s
Release / go-version (push) Successful in 7s
Release / release-notes (push) Failing after 24s
Release / Terraform Provider Release (push) Skipped
test / test (push) Failing after 4m19s
2024-02-14 13:17:58 -05:00
daniandDanielle Miu 7e7707d3af feat(policies): support storage policies within terraform (#558)
Co-authored-by: Danielle Miu <29378233+DanielleMiu@users.noreply.github.com>
2024-02-13 16:22:18 -08:00
Jeff Mitchell 8c12b27f8f Add support for grant_scope_ids (#562) 2024-02-13 15:01:48 -05:00
Jeff Mitchell 93e41ae83d Add id warning (#563)
* Add id warning

This adds a warning about using id in grants, which is no longer
supported when running against 0.15+.

* Add to Create as well
2024-02-09 15:30:13 -05:00
Jeff Mitchell bbc5889404 Fix space at beginning of description 2024-02-08 09:15:26 -05:00
Elim Tsiagbey 933192280b docs: Add required field for storage bucket example (#557)
Update example for dynamic credential for storage bucket to include `disable_credential_rotation` attribute. `disable_credential_rotation` needs to be set to true when configuring dynamic credentials
2024-02-06 11:00:46 -05:00
20 changed files with 1085 additions and 112 deletions

No files matched your search

+11 -1
View File
@@ -2,11 +2,21 @@
Canonical reference for changes, improvements, and bugfixes for the Boundary Terraform provider.
## 1.1.14 (February 14, 2024)
### New and Improved
* Support the multi-value `grant_scope_ids` field in the role provider
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/562))
* Support Boundary [Storage Policies](https://developer.hashicorp.com/boundary/docs/configuration/session-recording/configure-storage-policy)
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/558))
## 1.1.13 (February 1, 2024)
### New and Improved
* Allow dynamic credentials when configuring storage buckets.
* Allow dynamic credentials when configuring storage buckets
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/549))
## 1.1.12 (January 8, 2024)
+33
View File
@@ -0,0 +1,33 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "boundary_policy_storage Resource - terraform-provider-boundary"
subcategory: ""
description: |-
The storage policy resource allows you to configure a Boundary storage policy. Storage policies allow an admin to configure how long session recordings must be stored and when to delete them. Storage policies must be applied to the global scope or an org scope in order to take effect.
---
# boundary_policy_storage (Resource)
The storage policy resource allows you to configure a Boundary storage policy. Storage policies allow an admin to configure how long session recordings must be stored and when to delete them. Storage policies must be applied to the global scope or an org scope in order to take effect.
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `scope_id` (String) The scope for this policy.
### Optional
- `delete_after_days` (Number) The number of days after which a session recording will be automatically deleted. Defaults to 0: never automatically delete. However, delete_after_days and retain_for_days cannot both be 0.
- `delete_after_overridable` (Boolean) Whether or not the associated delete_after_days value can be overridden by org scopes. Note: if the associated delete_after_days value is 0, overridable is ignored
- `description` (String) The policy description.
- `name` (String) The policy name. Defaults to the resource name.
- `retain_for_days` (Number) The number of days a session recording is required to be stored. Defaults to 0: allow deletions at any time. However, retain_for_days and delete_after_days cannot both be 0.
- `retain_for_overridable` (Boolean) Whether or not the associated retain_for_days value can be overridden by org scopes. Note: if the associated retain_for_days value is 0, overridable is ignored.
### Read-Only
- `id` (String) The ID of the policy.
+2 -1
View File
@@ -127,7 +127,8 @@ resource "boundary_role" "readonly" {
### Optional
- `description` (String) The role description.
- `grant_scope_id` (String)
- `grant_scope_id` (String, Deprecated) For Boundary 0.15+, use `grant_scope_ids` instead. The scope for which the grants in the role should apply.
- `grant_scope_ids` (Set of String) A list of scopes for which the grants in this role should apply, which can include the special values "this", "children", or "descendants"
- `grant_strings` (Set of String) A list of stringified grants for the role.
- `name` (String) The role name. Defaults to the resource name.
- `principal_ids` (Set of String) A list of principal (user or group) IDs to add as principals on the role.
+4 -4
View File
@@ -53,10 +53,10 @@ resource "boundary_scope" "org" {
}
resource "boundary_role" "org_admin" {
scope_id = boundary_scope.global.id
grant_scope_id = boundary_scope.org.id
grant_strings = ["ids=*;type=*;actions=*"]
principal_ids = ["u_auth"]
scope_id = boundary_scope.global.id
grant_scope_ids = [boundary_scope.org.id]
grant_strings = ["ids=*;type=*;actions=*"]
principal_ids = ["u_auth"]
}
```
+25
View File
@@ -0,0 +1,25 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "boundary_scope_policy_attachment Resource - terraform-provider-boundary"
subcategory: ""
description: |-
---
# boundary_scope_policy_attachment (Resource)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `policy_id` (String)
- `scope_id` (String)
### Read-Only
- `id` (String) The ID of this resource.
+3 -2
View File
@@ -48,8 +48,9 @@ resource "boundary_storage_bucket" "aws_dynamic_credentials_example" {
# the role_arn value should be the same arn used as the instance profile that is attached to the ec2 instance
# https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html
attributes_json = jsonencode({
"region" = "us-east-1"
"role_arn" = "arn:aws:iam::123456789012:role/S3Access"
"region" = "us-east-1"
"role_arn" = "arn:aws:iam::123456789012:role/S3Access"
"disable_credential_rotation" = "true"
})
worker_filter = "\"pki\" in \"/tags/type\""
}
@@ -0,0 +1,27 @@
resource "boundary_scope" "global" {
global_scope = true
scope_id = "global"
}
resource "boundary_scope" "org" {
name = "organization_one"
description = "My first scope!"
scope_id = boundary_scope.global.id
auto_create_admin_role = true
auto_create_default_role = true
}
resource "boundary_policy_storage" "foo" {
name = "foo"
description = "Foo policy"
scope_id = boundary_scope.org.id
retain_for_days = 10
retain_for_overridable = false
delete_after_days = 10
delete_after_overridable = true
}
resource "boundary_scope_policy_attachment" "foo_attachment" {
scope_id = boundary_scope.org.id
policy_id = boundary_policy_storage.foo.id
}
+4 -4
View File
@@ -5,8 +5,8 @@ resource "boundary_scope" "org" {
}
resource "boundary_role" "org_admin" {
scope_id = boundary_scope.global.id
grant_scope_id = boundary_scope.org.id
grant_strings = ["ids=*;type=*;actions=*"]
principal_ids = ["u_auth"]
scope_id = boundary_scope.global.id
grant_scope_ids = [boundary_scope.org.id]
grant_strings = ["ids=*;type=*;actions=*"]
principal_ids = ["u_auth"]
}
@@ -33,8 +33,9 @@ resource "boundary_storage_bucket" "aws_dynamic_credentials_example" {
# the role_arn value should be the same arn used as the instance profile that is attached to the ec2 instance
# https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html
attributes_json = jsonencode({
"region" = "us-east-1"
"role_arn" = "arn:aws:iam::123456789012:role/S3Access"
"region" = "us-east-1"
"role_arn" = "arn:aws:iam::123456789012:role/S3Access"
"disable_credential_rotation" = "true"
})
worker_filter = "\"pki\" in \"/tags/type\""
}
}
+21 -21
View File
@@ -5,23 +5,23 @@ go 1.21.5
require (
github.com/YakDriver/regexache v0.23.0
github.com/hashicorp/boundary v0.15.0
github.com/hashicorp/boundary/api v0.0.45
github.com/hashicorp/boundary/sdk v0.0.42
github.com/hashicorp/cap v0.4.1
github.com/hashicorp/cap/ldap v0.0.0-20231012003312-273118a6e3b8
github.com/hashicorp/boundary/api v0.0.46-0.20240209231500-1b1c8b3bf9a6
github.com/hashicorp/boundary/sdk v0.0.43-0.20240209231500-1b1c8b3bf9a6
github.com/hashicorp/cap v0.5.0
github.com/hashicorp/cap/ldap v0.0.0-20240206183135-ed8f24513744
github.com/hashicorp/go-cty v1.4.1-0.20200723130312-85980079f637
github.com/hashicorp/go-kms-wrapping/v2 v2.0.15
github.com/hashicorp/go-kms-wrapping/v2 v2.0.16
github.com/hashicorp/go-secure-stdlib/configutil/v2 v2.0.11
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8
github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.6
github.com/hashicorp/terraform-plugin-docs v0.18.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.31.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.32.0
github.com/jimlambrt/gldap v0.1.9
github.com/kr/pretty v0.3.1
github.com/mitchellh/go-homedir v1.1.0
github.com/stretchr/testify v1.8.4
golang.org/x/crypto v0.18.0
mvdan.cc/gofumpt v0.5.0
golang.org/x/crypto v0.19.0
mvdan.cc/gofumpt v0.6.0
)
require (
@@ -108,7 +108,7 @@ require (
github.com/hashicorp/nodeenrollment v0.2.9 // indirect
github.com/hashicorp/terraform-exec v0.20.0 // indirect
github.com/hashicorp/terraform-json v0.21.0 // indirect
github.com/hashicorp/terraform-plugin-go v0.20.0 // indirect
github.com/hashicorp/terraform-plugin-go v0.21.0 // indirect
github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect
github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
@@ -181,24 +181,24 @@ require (
github.com/yuin/goldmark v1.6.0 // indirect
github.com/yuin/goldmark-meta v1.1.0 // indirect
github.com/zalando/go-keyring v0.2.3 // indirect
github.com/zclconf/go-cty v1.14.1 // indirect
github.com/zclconf/go-cty v1.14.2 // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/oauth2 v0.13.0 // indirect
golang.org/x/sync v0.4.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/term v0.16.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/oauth2 v0.14.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/term v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.14.0 // indirect
golang.org/x/tools v0.17.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/grpc v1.60.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/grpc v1.61.0 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/driver/postgres v1.5.4 // indirect
+44 -44
View File
@@ -134,8 +134,8 @@ github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4Nij
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
@@ -233,14 +233,14 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk=
github.com/hashicorp/boundary v0.15.0 h1:np75Igvt9ICQN3ZXJsXw91P5QFsvGDsNYoBNMFGeRcw=
github.com/hashicorp/boundary v0.15.0/go.mod h1:CJxelVYlFu4fU85wtxi50swKrVg665/GiIpd1Cxez1I=
github.com/hashicorp/boundary/api v0.0.45 h1:N4ZIjsYf4cwVfcW5sv0WitWiFr8UyudjA/ozCRkCckw=
github.com/hashicorp/boundary/api v0.0.45/go.mod h1:UrsSgLDpFmG6Eq+OIdpC8BSwbHwklsxL/ZCWklr0g5A=
github.com/hashicorp/boundary/sdk v0.0.42 h1:iRDdnM6/6q9qLtBP7/cpq/FWQGf69TFSsBQFxgGK8Jw=
github.com/hashicorp/boundary/sdk v0.0.42/go.mod h1:QJhm4rky2YMtk9DS5Rj8QJhDKB/6zQbVrm3R0QgdYmQ=
github.com/hashicorp/cap v0.4.1 h1:LVYrTLbPV8W6DPwIm/zC/fbc4UTpCQ7nJhCAPshLuG4=
github.com/hashicorp/cap v0.4.1/go.mod h1:oOoohCNd2JAgfvLz2NpFJTZiZ6CqH9dW8dZ2js52lGA=
github.com/hashicorp/cap/ldap v0.0.0-20231012003312-273118a6e3b8 h1:IKSRg1IONHl9ouMwx/Un1OVwdnlqVGWXRjUEg6VQZuY=
github.com/hashicorp/cap/ldap v0.0.0-20231012003312-273118a6e3b8/go.mod h1:EywAf3IOjdKgFT/mK1YQhHcNXuwDvG4FOuLs1L1odh0=
github.com/hashicorp/boundary/api v0.0.46-0.20240209231500-1b1c8b3bf9a6 h1:6/GdZZDW8ChPduD9rFnr8VGZmTPGGvlMrtELWqmoz8I=
github.com/hashicorp/boundary/api v0.0.46-0.20240209231500-1b1c8b3bf9a6/go.mod h1:UrsSgLDpFmG6Eq+OIdpC8BSwbHwklsxL/ZCWklr0g5A=
github.com/hashicorp/boundary/sdk v0.0.43-0.20240209231500-1b1c8b3bf9a6 h1:DIfWtA4OOcCJlIL3LJUERF7M90ephrEgn16KWWDX2KU=
github.com/hashicorp/boundary/sdk v0.0.43-0.20240209231500-1b1c8b3bf9a6/go.mod h1:QJhm4rky2YMtk9DS5Rj8QJhDKB/6zQbVrm3R0QgdYmQ=
github.com/hashicorp/cap v0.5.0 h1:YIlAYxdXXtx2IL1JDvP2OyEl55Ooi0yl573kSB9Orlw=
github.com/hashicorp/cap v0.5.0/go.mod h1:IAy00Er+ZFpMo+5x6B4bkO2HgpzgrkfsuDWMmHAuKUE=
github.com/hashicorp/cap/ldap v0.0.0-20240206183135-ed8f24513744 h1:6cU01ORaCUxRXRS0YYnmm4tMfAvFRjamhjgMrgmoWZs=
github.com/hashicorp/cap/ldap v0.0.0-20240206183135-ed8f24513744/go.mod h1:SOJuo/OFD0qKQ7d8qOy+a2B9Tw0/97oHIo+qXxs7HZE=
github.com/hashicorp/cli v1.1.6 h1:CMOV+/LJfL1tXCOKrgAX0uRKnzjj/mpmqNXloRSy2K8=
github.com/hashicorp/cli v1.1.6/go.mod h1:MPon5QYlgjjo0BSoAiN0ESeT5fRzDjVRp+uioJ0piz4=
github.com/hashicorp/dbassert v0.0.0-20231012105025-1bc1bd88e22b h1:rvg3eCucdlpfsnbYXM1Ett4f0reNmIuCruyJUF4iw/0=
@@ -275,8 +275,8 @@ github.com/hashicorp/go-kms-wrapping/extras/kms/v2 v2.0.0-20231124110655-4315424
github.com/hashicorp/go-kms-wrapping/extras/kms/v2 v2.0.0-20231124110655-4315424d22d0/go.mod h1:EHsJEWJkTl6vZ9OUCpfvH8aaLtkmjYdtIpQgzYvw4vI=
github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5 h1:jrnDfQm2hCQ0/hEselgqzV4fK16gpZoY0OWGZpVPNHM=
github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5/go.mod h1:psh1qKep5ukvuNobFY/hCybuudlkkACpmazOsCgX5Rg=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.15 h1:f3+/VbanXOmVAaDBKwRiVmeL7EX340a4YmaTItMF4Xs=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.15/go.mod h1:0dWtzl2ilqKpavgM3id/kFK9L3tjo6fS4OhbVPSYpnQ=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.16/go.mod h1:ZiKZctjRTLEppuRwrttWkp71VYMbTTCkazK4xT7U/NQ=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
@@ -346,12 +346,12 @@ github.com/hashicorp/terraform-json v0.21.0 h1:9NQxbLNqPbEMze+S6+YluEdXgJmhQykRy
github.com/hashicorp/terraform-json v0.21.0/go.mod h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk=
github.com/hashicorp/terraform-plugin-docs v0.18.0 h1:2bINhzXc+yDeAcafurshCrIjtdu1XHn9zZ3ISuEhgpk=
github.com/hashicorp/terraform-plugin-docs v0.18.0/go.mod h1:iIUfaJpdUmpi+rI42Kgq+63jAjI8aZVTyxp3Bvk9Hg8=
github.com/hashicorp/terraform-plugin-go v0.20.0 h1:oqvoUlL+2EUbKNsJbIt3zqqZ7wi6lzn4ufkn/UA51xQ=
github.com/hashicorp/terraform-plugin-go v0.20.0/go.mod h1:Rr8LBdMlY53a3Z/HpP+ZU3/xCDqtKNCkeI9qOyT10QE=
github.com/hashicorp/terraform-plugin-go v0.21.0 h1:VSjdVQYNDKR0l2pi3vsFK1PdMQrw6vGOshJXMNFeVc0=
github.com/hashicorp/terraform-plugin-go v0.21.0/go.mod h1:piJp8UmO1uupCvC9/H74l2C6IyKG0rW4FDedIpwW5RQ=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.31.0 h1:Bl3e2ei2j/Z3Hc2HIS15Gal2KMKyLAZ2om1HCEvK6es=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.31.0/go.mod h1:i2C41tszDjiWfziPQDL5R/f3Zp0gahXe5No/MIO9rCE=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.32.0 h1:7xdO9aOXVmhvMxNAq8UloyyqW0EEzyAY37llSTHJgjo=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.32.0/go.mod h1:LxQzs7AQl/5JE1IGFd6LX8E4A0InRJ/7s245gOmsejA=
github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI=
github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM=
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
@@ -669,8 +669,8 @@ github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUei
github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0=
github.com/zalando/go-keyring v0.2.3 h1:v9CUu9phlABObO4LPWycf+zwMG7nlbb3t/B5wa97yms=
github.com/zalando/go-keyring v0.2.3/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk=
github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA=
github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty v1.14.2 h1:kTG7lqmBou0Zkx35r6HJHUQTvaRPr5bIAf3AoHS0izI=
github.com/zclconf/go-cty v1.14.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -715,8 +715,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
@@ -757,12 +757,12 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0=
golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -771,8 +771,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -808,8 +808,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -818,8 +818,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -855,8 +855,8 @@ golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -873,12 +873,12 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 h1:I6WNifs6pF9tNdSob2W24JtyxIYjzFB9qDlpUC76q+U=
google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4=
google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405 h1:HJMDndgxest5n2y77fnErkM62iUsptE/H8p0dC2Huo4=
google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405/go.mod h1:oT32Z4o8Zv2xPQTg0pbVaPr0MPOH6f14RgXt7zfIpwg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
@@ -889,8 +889,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
google.golang.org/grpc v1.60.0 h1:6FQAR0kM31P6MRdeluor2w2gPaS4SVNrD/DNTxrQ15k=
google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0=
google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -902,8 +902,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -948,7 +948,7 @@ modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48=
mvdan.cc/gofumpt v0.5.0 h1:0EQ+Z56k8tXjj/6TQD25BFNKQXpCvT0rnansIc7Ug5E=
mvdan.cc/gofumpt v0.5.0/go.mod h1:HBeVDtMKRZpXyxFciAirzdKklDlGu8aAy1wEbH5Y9js=
mvdan.cc/gofumpt v0.6.0 h1:G3QvahNDmpD+Aek/bNOLrFR2XC6ZAdo62dZu65gmwGo=
mvdan.cc/gofumpt v0.6.0/go.mod h1:4L0wf+kgIPZtcCWXynNS2e6bhmj73umwnuXSZarixzA=
nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q=
nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
+1 -1
View File
@@ -42,7 +42,7 @@ resource "boundary_scope" "project" {
resource "boundary_role" "org_admin" {
scope_id = "global"
grant_scope_id = boundary_scope.org.id
grant_scope_ids = [boundary_scope.org.id]
grant_strings = ["ids=*;type=*;actions=*"]
principal_ids = ["u_auth"]
}
+2
View File
@@ -120,6 +120,8 @@ func New() *schema.Provider {
"boundary_host_set": resourceHostSet(),
"boundary_host_set_static": resourceHostSetStatic(),
"boundary_host_set_plugin": resourceHostSetPlugin(),
"boundary_policy_storage": resourcePolicyStorage(),
"boundary_scope_policy_attachment": resourceScopePolicyAttachment(),
"boundary_role": resourceRole(),
"boundary_scope": resourceScope(),
"boundary_storage_bucket": resourceStorageBucket(),
@@ -92,7 +92,7 @@ resource "boundary_user" "alice" {
resource "boundary_role" "ldap_principal" {
scope_id = boundary_scope.global.id
grant_scope_id = boundary_scope.global.id
grant_scope_ids = [boundary_scope.global.id]
grant_strings = ["ids=*;type=*;actions=*"]
principal_ids = [boundary_user.alice.id]
}`
@@ -0,0 +1,303 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package provider
import (
"context"
"net/http"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/policies"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (
policyStorageRetainForDaysKey = "retain_for_days"
policyStorageRetainForOverridableKey = "retain_for_overridable"
policyStorageDeleteAfterDaysKey = "delete_after_days"
policyStorageDeleteAfterOverridableKey = "delete_after_overridable"
policyTypeStorage = "storage"
daysField = "days"
overridableField = "overridable"
)
func resourcePolicyStorage() *schema.Resource {
return &schema.Resource{
Description: "The storage policy resource allows you to configure a Boundary storage policy. " +
"Storage policies allow an admin to configure how long session recordings must be stored and when " +
"to delete them. Storage policies must be applied to the global scope or an org scope in order to take effect.",
CreateContext: resourcePolicyStorageCreate,
ReadContext: resourcePolicyStorageRead,
UpdateContext: resourcePolicyStorageUpdate,
DeleteContext: resourcePolicyStorageDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Schema: map[string]*schema.Schema{
IDKey: {
Description: "The ID of the policy.",
Type: schema.TypeString,
Computed: true,
},
NameKey: {
Description: "The policy name. Defaults to the resource name.",
Type: schema.TypeString,
Optional: true,
},
DescriptionKey: {
Description: "The policy description.",
Type: schema.TypeString,
Optional: true,
},
ScopeIdKey: {
Description: "The scope for this policy.",
Type: schema.TypeString,
Required: true,
},
policyStorageRetainForDaysKey: {
Description: "The number of days a session recording is required to be stored. Defaults to 0: allow deletions at any time. However, " + policyStorageRetainForDaysKey + " and " + policyStorageDeleteAfterDaysKey + " cannot both be 0.",
Type: schema.TypeInt,
Optional: true,
AtLeastOneOf: []string{policyStorageDeleteAfterDaysKey},
},
policyStorageRetainForOverridableKey: {
Description: "Whether or not the associated " + policyStorageRetainForDaysKey + " value can be overridden by org scopes. Note: if the associated " + policyStorageRetainForDaysKey + " value is 0, overridable is ignored.",
Type: schema.TypeBool,
Optional: true,
},
policyStorageDeleteAfterDaysKey: {
Description: "The number of days after which a session recording will be automatically deleted. Defaults to 0: never automatically delete. However, " + policyStorageDeleteAfterDaysKey + " and " + policyStorageRetainForDaysKey + " cannot both be 0.",
Type: schema.TypeInt,
Optional: true,
AtLeastOneOf: []string{policyStorageRetainForDaysKey},
},
policyStorageDeleteAfterOverridableKey: {
Description: "Whether or not the associated " + policyStorageDeleteAfterDaysKey + " value can be overridden by org scopes. Note: if the associated " + policyStorageDeleteAfterDaysKey + " value is 0, overridable is ignored",
Type: schema.TypeBool,
Optional: true,
},
},
}
}
func setFromPolicyItem(d *schema.ResourceData, p *policies.Policy) error {
d.SetId(p.Id)
if err := d.Set(NameKey, p.Name); err != nil {
return err
}
if err := d.Set(DescriptionKey, p.Description); err != nil {
return err
}
if err := d.Set(ScopeIdKey, p.ScopeId); err != nil {
return err
}
// parse attributes to the retain/delete values so that the tf syntax is simpler
attributes, err := p.GetStoragePolicyAttributes()
if err != nil {
return err
}
// retain_for attribute
if attributes.RetainFor != nil {
if err := d.Set(policyStorageRetainForDaysKey, attributes.RetainFor.Days); err != nil {
return err
}
if err := d.Set(policyStorageRetainForOverridableKey, attributes.RetainFor.Overridable); err != nil {
return err
}
} else {
// no RetainFor, set to nil
if err := d.Set(policyStorageRetainForDaysKey, nil); err != nil {
return err
}
if err := d.Set(policyStorageRetainForOverridableKey, nil); err != nil {
return err
}
}
// delete_after attribute
if attributes.DeleteAfter != nil {
if err := d.Set(policyStorageDeleteAfterDaysKey, attributes.DeleteAfter.Days); err != nil {
return err
}
if err := d.Set(policyStorageDeleteAfterOverridableKey, attributes.DeleteAfter.Overridable); err != nil {
return err
}
} else {
// no DeleteAfter, set to nil
if err := d.Set(policyStorageDeleteAfterDaysKey, nil); err != nil {
return err
}
if err := d.Set(policyStorageDeleteAfterOverridableKey, nil); err != nil {
return err
}
}
return nil
}
func resourcePolicyStorageCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
pClient := policies.NewClient(md.client)
opts := []policies.Option{}
var scopeId string
if scopeIdVal, ok := d.GetOk(ScopeIdKey); ok {
scopeId = scopeIdVal.(string)
} else {
return diag.Errorf("no scope ID provided")
}
if nameVal, ok := d.GetOk(NameKey); ok {
opts = append(opts, policies.WithName(nameVal.(string)))
}
if descVal, ok := d.GetOk(DescriptionKey); ok {
opts = append(opts, policies.WithDescription(descVal.(string)))
}
if retainDaysVal, ok := d.GetOk(policyStorageRetainForDaysKey); ok {
opts = append(opts, policies.WithStoragePolicyRetainForDays(int32(retainDaysVal.(int))))
} else {
opts = append(opts, policies.DefaultStoragePolicyRetainForDays())
}
if retainOverrideVal, ok := d.GetOk(policyStorageRetainForOverridableKey); ok {
opts = append(opts, policies.WithStoragePolicyRetainForOverridable(retainOverrideVal.(bool)))
} else {
opts = append(opts, policies.DefaultStoragePolicyRetainForOverridable())
}
if deleteDaysVal, ok := d.GetOk(policyStorageDeleteAfterDaysKey); ok {
opts = append(opts, policies.WithStoragePolicyDeleteAfterDays(int32(deleteDaysVal.(int))))
} else {
opts = append(opts, policies.DefaultStoragePolicyDeleteAfterDays())
}
if deleteOverrideVal, ok := d.GetOk(policyStorageDeleteAfterOverridableKey); ok {
opts = append(opts, policies.WithStoragePolicyDeleteAfterOverridable(deleteOverrideVal.(bool)))
} else {
opts = append(opts, policies.DefaultStoragePolicyDeleteAfterOverridable())
}
p, err := pClient.Create(ctx, policyTypeStorage, scopeId, opts...)
if err != nil {
return diag.Errorf("error creating storage policy: %v", err)
}
if p == nil {
return diag.Errorf("nil storage policy after create")
}
if err := setFromPolicyItem(d, p.GetItem()); err != nil {
return diag.FromErr(err)
}
return nil
}
func resourcePolicyStorageRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
pClient := policies.NewClient(md.client)
p, err := pClient.Read(ctx, d.Id())
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
d.SetId("")
return nil
}
return diag.Errorf("error reading policy: %v", err)
}
if p == nil {
return diag.Errorf("policy nil after read")
}
if err := setFromPolicyItem(d, p.GetItem()); err != nil {
return diag.FromErr(err)
}
return nil
}
func resourcePolicyStorageUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
pClient := policies.NewClient(md.client)
opts := []policies.Option{}
if d.HasChange(NameKey) {
if nameVal, ok := d.GetOk(NameKey); ok {
name := nameVal.(string)
opts = append(opts, policies.WithName(name))
} else {
opts = append(opts, policies.DefaultName())
}
}
if d.HasChange(DescriptionKey) {
if descriptionVal, ok := d.GetOk(DescriptionKey); ok {
description := descriptionVal.(string)
opts = append(opts, policies.WithDescription(description))
} else {
opts = append(opts, policies.DefaultDescription())
}
}
if d.HasChanges(policyStorageRetainForDaysKey, policyStorageRetainForOverridableKey) {
if retainDaysVal, ok := d.GetOk(policyStorageRetainForDaysKey); ok {
opts = append(opts, policies.WithStoragePolicyRetainForDays(int32(retainDaysVal.(int))))
} else {
opts = append(opts, policies.DefaultStoragePolicyRetainForDays())
}
if retainOverrideVal, ok := d.GetOk(policyStorageRetainForOverridableKey); ok {
opts = append(opts, policies.WithStoragePolicyRetainForOverridable(retainOverrideVal.(bool)))
} else {
opts = append(opts, policies.DefaultStoragePolicyRetainForOverridable())
}
}
if d.HasChanges(policyStorageDeleteAfterDaysKey, policyStorageDeleteAfterOverridableKey) {
if deleteDaysVal, ok := d.GetOk(policyStorageDeleteAfterDaysKey); ok {
opts = append(opts, policies.WithStoragePolicyDeleteAfterDays(int32(deleteDaysVal.(int))))
} else {
opts = append(opts, policies.DefaultStoragePolicyDeleteAfterDays())
}
if deleteOverrideVal, ok := d.GetOk(policyStorageDeleteAfterOverridableKey); ok {
opts = append(opts, policies.WithStoragePolicyDeleteAfterOverridable(deleteOverrideVal.(bool)))
} else {
opts = append(opts, policies.DefaultStoragePolicyDeleteAfterOverridable())
}
}
if len(opts) > 0 {
opts = append(opts, policies.WithAutomaticVersioning(true))
p, err := pClient.Update(ctx, d.Id(), 0, opts...)
if err != nil {
return diag.Errorf("error creating storage policy: %v", err)
}
if p == nil {
return diag.Errorf("nil storage policy after create")
}
if err := setFromPolicyItem(d, p.GetItem()); err != nil {
return diag.FromErr(err)
}
}
return nil
}
func resourcePolicyStorageDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
pClient := policies.NewClient(md.client)
_, err := pClient.Delete(ctx, d.Id())
if err != nil {
return diag.Errorf("error deleting policy: %v", err)
}
return nil
}
+133 -22
View File
@@ -5,7 +5,12 @@ package provider
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"unicode"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/roles"
@@ -14,9 +19,10 @@ import (
)
const (
roleGrantScopeIdKey = "grant_scope_id"
rolePrincipalIdsKey = "principal_ids"
roleGrantStringsKey = "grant_strings"
roleGrantScopeIdKey = "grant_scope_id"
roleGrantScopeIdsKey = "grant_scope_ids"
rolePrincipalIdsKey = "principal_ids"
roleGrantStringsKey = "grant_strings"
)
func resourceRole() *schema.Resource {
@@ -60,15 +66,24 @@ func resourceRole() *schema.Resource {
Elem: &schema.Schema{Type: schema.TypeString},
},
roleGrantStringsKey: {
Description: " A list of stringified grants for the role.",
Description: "A list of stringified grants for the role.",
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
roleGrantScopeIdKey: {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "For Boundary 0.15+, use `grant_scope_ids` instead. The scope for which the grants in the role should apply.",
Type: schema.TypeString,
Optional: true,
Computed: true,
Deprecated: "In Boundary 0.15+, please use `grant_scope_ids` instead. This field will be removed in a future release.",
},
roleGrantScopeIdsKey: {
Description: `A list of scopes for which the grants in this role should apply, which can include the special values "this", "children", or "descendants"`,
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Computed: true,
},
},
}
@@ -90,14 +105,18 @@ func setFromRoleResponseMap(d *schema.ResourceData, raw map[string]interface{})
if err := d.Set(roleGrantStringsKey, raw["grant_strings"]); err != nil {
return err
}
if err := d.Set(roleGrantScopeIdsKey, raw["grant_scope_ids"]); err != nil {
return err
}
if err := d.Set(roleGrantScopeIdKey, raw["grant_scope_id"]); err != nil {
return err
}
d.SetId(raw["id"].(string))
return nil
}
func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) (errs diag.Diagnostics) {
func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) (diags diag.Diagnostics) {
md := meta.(*metaData)
var scopeId string
@@ -121,11 +140,19 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
opts = append(opts, roles.WithDescription(descStr))
}
grantScopeIdVal, ok := d.GetOk(roleGrantScopeIdKey)
if ok {
grantScopeIdVal := d.Get(roleGrantScopeIdKey)
if grantScopeIdVal != "" {
grantScopeIdStr := grantScopeIdVal.(string)
opts = append(opts, roles.WithGrantScopeId(grantScopeIdStr))
}
var grantScopeIds []string
if grantScopeIdsVal, ok := d.GetOk(roleGrantScopeIdsKey); ok {
list := grantScopeIdsVal.(*schema.Set).List()
grantScopeIds = make([]string, 0, len(list))
for _, i := range list {
grantScopeIds = append(grantScopeIds, i.(string))
}
}
var principalIds []string
if principalIdsVal, ok := d.GetOk(rolePrincipalIdsKey); ok {
@@ -141,6 +168,16 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
list := grantStringsVal.(*schema.Set).List()
grantStrings = make([]string, 0, len(list))
for _, i := range list {
for _, grant := range list {
deprecationNotice, err := checkGrantForDeprecation(grant.(string))
if err != nil {
return diag.FromErr(err)
}
if deprecationNotice != "" {
diags = append(diags, diag.Diagnostic{Severity: diag.Warning, Summary: "deprecated field found in grant", Detail: deprecationNotice})
}
grantStrings = append(grantStrings, grant.(string))
}
grantStrings = append(grantStrings, i.(string))
}
}
@@ -157,7 +194,7 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
apiResponse := tcr.GetResponse().Map
defer func() {
if err := setFromRoleResponseMap(d, apiResponse); err != nil {
errs = append(errs, diag.FromErr(err)...)
diags = append(diags, diag.FromErr(err)...)
}
}()
@@ -165,9 +202,9 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
tspr, err := rc.SetPrincipals(ctx, tcr.Item.Id, 0, principalIds, roles.WithAutomaticVersioning(true))
switch {
case err != nil:
errs = append(errs, diag.Diagnostic{Severity: diag.Error, Summary: "error setting principals", Detail: err.Error()})
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "error setting principals", Detail: err.Error()})
case tspr == nil:
errs = append(errs, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting principals"})
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting principals"})
default:
apiResponse = tspr.GetResponse().Map
}
@@ -177,15 +214,27 @@ func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interf
tsgr, err := rc.SetGrants(ctx, tcr.Item.Id, 0, grantStrings, roles.WithAutomaticVersioning(true))
switch {
case err != nil:
errs = append(errs, diag.Diagnostic{Severity: diag.Error, Summary: "error setting grants", Detail: err.Error()})
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "error setting grants", Detail: err.Error()})
case tsgr == nil:
errs = append(errs, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting grants"})
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting grants"})
default:
apiResponse = tsgr.GetResponse().Map
}
}
return errs
if grantScopeIds != nil {
tsgr, err := rc.SetGrantScopes(ctx, tcr.Item.Id, 0, grantScopeIds, roles.WithAutomaticVersioning(true))
switch {
case err != nil:
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "error setting grant scopes", Detail: err.Error()})
case tsgr == nil:
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "nil role after setting grant scope ids"})
default:
apiResponse = tsgr.GetResponse().Map
}
}
return diags
}
func resourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
@@ -241,12 +290,17 @@ func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interf
var grantScopeId *string
if d.HasChange(roleGrantScopeIdKey) {
opts = append(opts, roles.DefaultGrantScopeId())
grantScopeIdVal, ok := d.GetOk(roleGrantScopeIdKey)
if ok {
grantScopeIdStr := grantScopeIdVal.(string)
grantScopeId = &grantScopeIdStr
opts = append(opts, roles.WithGrantScopeId(grantScopeIdStr))
// If it is an update to use the multi-value grant_scope_ids, and this
// has changed to "", then don't set it on the API. Instead let it fall
// through and below it'll be updated to be "".
if !d.HasChange(roleGrantScopeIdsKey) {
opts = append(opts, roles.DefaultGrantScopeId())
grantScopeIdVal, ok := d.GetOk(roleGrantScopeIdKey)
if ok {
grantScopeIdStr := grantScopeIdVal.(string)
grantScopeId = &grantScopeIdStr
opts = append(opts, roles.WithGrantScopeId(grantScopeIdStr))
}
}
}
@@ -280,6 +334,13 @@ func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interf
if grantStringsVal, ok := d.GetOk(roleGrantStringsKey); ok {
grants := grantStringsVal.(*schema.Set).List()
for _, grant := range grants {
deprecationNotice, err := checkGrantForDeprecation(grant.(string))
if err != nil {
return diag.FromErr(err)
}
if deprecationNotice != "" {
diags = append(diags, diag.Diagnostic{Severity: diag.Warning, Summary: "deprecated field found in grant", Detail: deprecationNotice})
}
grantStrings = append(grantStrings, grant.(string))
}
}
@@ -311,6 +372,24 @@ func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, meta interf
}
}
if d.HasChange(roleGrantScopeIdsKey) {
var grantScopeIds []string
if grantScopeIdsVal, ok := d.GetOk(roleGrantScopeIdsKey); ok {
grantScopes := grantScopeIdsVal.(*schema.Set).List()
for _, grantScope := range grantScopes {
grantScopeIds = append(grantScopeIds, grantScope.(string))
}
}
_, err := rc.SetGrantScopes(ctx, d.Id(), 0, grantScopeIds, roles.WithAutomaticVersioning(true))
if err != nil {
diags = append(diags, diag.Diagnostic{Severity: diag.Error, Summary: "error setting grant scopes", Detail: err.Error()})
} else {
if err := d.Set(roleGrantScopeIdsKey, grantScopeIds); err != nil {
return diag.FromErr(err)
}
}
}
return diags
}
@@ -325,3 +404,35 @@ func resourceRoleDelete(ctx context.Context, d *schema.ResourceData, meta interf
return nil
}
func checkGrantForDeprecation(grantString string) (string, error) {
if len(grantString) == 0 {
return "", errors.New("missing grant string")
}
grantString = strings.ToValidUTF8(grantString, string(unicode.ReplacementChar))
switch {
case grantString[0] == '{':
raw := make(map[string]any, 4)
if err := json.Unmarshal([]byte(grantString), &raw); err != nil {
return "", fmt.Errorf("error json unmarshalling grant string: %w", err)
}
if raw["id"] != nil {
return `Grant contains an "id" field which is deprecated and will not be accepted from Boundary 0.15+. Please use "ids" instead.`, nil
}
default:
parts := strings.Split(grantString, ";")
for _, part := range parts {
splitPart := strings.Split(part, "=")
if len(splitPart) < 2 {
return "", fmt.Errorf("invalid grant part: %s", part)
}
if splitPart[0] == "id" {
return `Grant contains an "id" field which is deprecated and will not be accepted from Boundary 0.15+. Please use "ids" instead.`, nil
}
}
}
return "", nil
}
@@ -0,0 +1,295 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package provider
import (
"context"
"fmt"
"regexp"
"testing"
"github.com/hashicorp/boundary/api/roles"
"github.com/hashicorp/boundary/testing/controller"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
var (
orgRoleWithGrantScopes = `
resource "boundary_role" "with_grant_scopes" {
name = "with_grant_scopes"
description = "with grant scopes"
principal_ids = [boundary_user.foo.id]
scope_id = boundary_scope.org1.id
depends_on = [boundary_role.org1_admin]
grant_scope_ids = ["this", "children", boundary_scope.proj1.id]
}`
orgRoleWithGrantScopesUpdate = `
resource "boundary_role" "with_grant_scopes" {
name = "with_grant_scopes_update"
description = "with grant scopes update"
principal_ids = [boundary_user.foo.id]
scope_id = boundary_scope.org1.id
depends_on = [boundary_role.org1_admin]
grant_scope_ids = ["this"]
}`
orgRoleWithInvalidGrantScopesUpdate = `
resource "boundary_role" "with_grant_scopes" {
name = "with_grant_scopes_update"
description = "with grant scopes update"
principal_ids = [boundary_user.foo.id]
scope_id = boundary_scope.org1.id
depends_on = [boundary_role.org1_admin]
grant_scope_ids = ["this", "children", "p_foobar1234"]
}`
conversionOrgRoleWithGrantScopeId = `
resource "boundary_role" "with_grant_scope_id" {
name = "grant scope id role"
scope_id = boundary_scope.org1.id
depends_on = [boundary_role.org1_admin]
grant_scope_id = boundary_scope.org1.id
}`
conversionOrgRoleWithGrantScopeIdUpdate = `
resource "boundary_role" "with_grant_scope_id" {
name = "grant scope id role"
scope_id = boundary_scope.org1.id
depends_on = [boundary_role.org1_admin]
grant_scope_id = boundary_scope.proj1.id
}`
conversionOrgRoleWithGrantScopeIdsConversion = `
resource "boundary_role" "with_grant_scope_id" {
name = "grant scope id role"
scope_id = boundary_scope.org1.id
depends_on = [boundary_role.org1_admin]
grant_scope_ids = ["this", boundary_scope.proj1.id]
}`
conversionOrgRoleWithGrantScopeIdsUpdate = `
resource "boundary_role" "with_grant_scope_id" {
name = "grant scope id role"
scope_id = boundary_scope.org1.id
depends_on = [boundary_role.org1_admin]
grant_scope_ids = ["this", "children"]
}`
)
// TestAccRoleWithGrantScopes exercises creation and update with valid and
// invalid grant scopes
func TestAccRoleWithGrantScopes(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...)
t.Cleanup(tc.Shutdown)
url := tc.ApiAddrs()[0]
var provider *schema.Provider
resource.Test(t, resource.TestCase{
IsUnitTest: true,
ProviderFactories: providerFactories(&provider),
CheckDestroy: testAccCheckRoleResourceDestroy(t, provider),
Steps: []resource.TestStep{
{
// Create with valid grant scopes should create role
Config: testConfig(url, fooOrg, firstProjectFoo, fooUser, orgRoleWithGrantScopes),
Check: resource.ComposeTestCheckFunc(
testAccCheckScopeResourceExists(provider, "boundary_scope.proj1"),
testAccCheckRoleResourceExists(provider, "boundary_role.with_grant_scopes"),
testAccCheckUserResourceExists(provider, "boundary_user.foo"),
testAccCheckRoleResourceGrantScopesSet(provider, "boundary_role.with_grant_scopes", []string{"this", "children", "boundary_scope.proj1"}),
resource.TestCheckResourceAttr("boundary_role.with_grant_scopes", DescriptionKey, "with grant scopes"),
resource.TestCheckResourceAttr("boundary_role.with_grant_scopes", NameKey, "with_grant_scopes"),
),
},
importStep("boundary_role.with_grant_scopes"),
{
// Update with invalid grant scopes should update role but return empty plan
// since grant scopes were not set correctly.
Config: testConfig(url, fooOrg, firstProjectFoo, fooUser, orgRoleWithInvalidGrantScopesUpdate),
Check: resource.ComposeTestCheckFunc(
testAccCheckRoleResourceExists(provider, "boundary_role.with_grant_scopes"),
resource.TestCheckResourceAttr("boundary_role.with_grant_scopes", DescriptionKey, "with grant scopes update"),
resource.TestCheckResourceAttr("boundary_role.with_grant_scopes", NameKey, "with_grant_scopes_update"),
),
ExpectError: regexp.MustCompile(`Unable to set grant scopes on role`),
},
{
// Update again without invalid principal should produce empty plan
Config: testConfig(url, fooOrg, firstProjectFoo, fooUser, orgRoleWithGrantScopesUpdate),
Check: resource.ComposeTestCheckFunc(
testAccCheckRoleResourceExists(provider, "boundary_role.with_grant_scopes"),
testAccCheckRoleResourceGrantScopesSet(provider, "boundary_role.with_grant_scopes", []string{"this"}),
resource.TestCheckResourceAttr("boundary_role.with_grant_scopes", DescriptionKey, "with grant scopes update"),
resource.TestCheckResourceAttr("boundary_role.with_grant_scopes", NameKey, "with_grant_scopes_update"),
),
},
importStep("boundary_role.with_grant_scopes"),
},
})
}
// TestAccRoleGrantScopeUpgrade exercises some specific upgrade scenarios around
// grant_scope_id -> grant_scope_ids
func TestAccRoleWithGrantScopesUpdate(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...)
t.Cleanup(tc.Shutdown)
url := tc.ApiAddrs()[0]
var provider *schema.Provider
resource.Test(t, resource.TestCase{
IsUnitTest: true,
ProviderFactories: providerFactories(&provider),
CheckDestroy: testAccCheckRoleResourceDestroy(t, provider),
Steps: []resource.TestStep{
{
// Create
Config: testConfig(url, fooOrg, firstProjectFoo, fooUser, conversionOrgRoleWithGrantScopeId),
Check: resource.ComposeTestCheckFunc(
testAccCheckScopeResourceExists(provider, "boundary_scope.org1"),
testAccCheckRoleResourceExists(provider, "boundary_role.with_grant_scope_id"),
testAccCheckUserResourceExists(provider, "boundary_user.foo"),
testAccCheckRoleResourceGrantScopesSet(provider, "boundary_role.with_grant_scope_id", []string{"boundary_scope.org1"}),
testAccCheckRoleResourceGrantScopeSet(provider, "boundary_role.with_grant_scope_id", "boundary_scope.org1"),
),
},
importStep("boundary_role.with_grant_scope_id"),
{
Config: testConfig(url, fooOrg, firstProjectFoo, fooUser, conversionOrgRoleWithGrantScopeIdUpdate),
Check: resource.ComposeTestCheckFunc(
testAccCheckScopeResourceExists(provider, "boundary_scope.org1"),
testAccCheckRoleResourceExists(provider, "boundary_role.with_grant_scope_id"),
testAccCheckUserResourceExists(provider, "boundary_user.foo"),
testAccCheckRoleResourceGrantScopesSet(provider, "boundary_role.with_grant_scope_id", []string{"boundary_scope.proj1"}),
testAccCheckRoleResourceGrantScopeSet(provider, "boundary_role.with_grant_scope_id", "boundary_scope.proj1"),
),
},
importStep("boundary_role.with_grant_scope_id"),
{
Config: testConfig(url, fooOrg, firstProjectFoo, fooUser, conversionOrgRoleWithGrantScopeIdsConversion),
Check: resource.ComposeTestCheckFunc(
testAccCheckScopeResourceExists(provider, "boundary_scope.org1"),
testAccCheckRoleResourceExists(provider, "boundary_role.with_grant_scope_id"),
testAccCheckUserResourceExists(provider, "boundary_user.foo"),
testAccCheckRoleResourceGrantScopesSet(provider, "boundary_role.with_grant_scope_id", []string{"this", "boundary_scope.proj1"}),
testAccCheckRoleResourceGrantScopeSet(provider, "boundary_role.with_grant_scope_id", ""),
),
},
importStep("boundary_role.with_grant_scope_id"),
{
Config: testConfig(url, fooOrg, firstProjectFoo, fooUser, conversionOrgRoleWithGrantScopeIdsUpdate),
Check: resource.ComposeTestCheckFunc(
testAccCheckScopeResourceExists(provider, "boundary_scope.org1"),
testAccCheckRoleResourceExists(provider, "boundary_role.with_grant_scope_id"),
testAccCheckUserResourceExists(provider, "boundary_user.foo"),
testAccCheckRoleResourceGrantScopesSet(provider, "boundary_role.with_grant_scope_id", []string{"this", "children"}),
testAccCheckRoleResourceGrantScopeSet(provider, "boundary_role.with_grant_scope_id", ""),
),
},
importStep("boundary_role.with_grant_scope_id"),
},
})
}
func testAccCheckRoleResourceGrantScopeSet(testProvider *schema.Provider, name string, grantScope string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("role resource not found: %s", name)
}
roleId := rs.Primary.ID
scopeId := grantScope
if grantScope != "children" && grantScope != "this" && grantScope != "descendants" && grantScope != "" {
scope, ok := s.RootModule().Resources[grantScope]
if !ok {
return fmt.Errorf("scope resource not found: %s", grantScope)
}
scopeId = scope.Primary.ID
if scopeId == "" {
return fmt.Errorf("role resource ID is not set")
}
}
md := testProvider.Meta().(*metaData)
rolesClient := roles.NewClient(md.client)
rr, err := rolesClient.Read(context.Background(), roleId)
if err != nil {
return fmt.Errorf("Got an error when reading role %q: %v", roleId, err)
}
if rr.Item.GrantScopeId != scopeId {
return fmt.Errorf("grant scope id in state is %s but in boundary is %s", scopeId, rr.Item.GrantScopeId)
}
return nil
}
}
func testAccCheckRoleResourceGrantScopesSet(testProvider *schema.Provider, name string, grantScopeIds []string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("role resource not found: %s", name)
}
id := rs.Primary.ID
if id == "" {
return fmt.Errorf("role resource ID is not set")
}
scopeIds := []string{}
for _, grantScope := range grantScopeIds {
if grantScope == "children" || grantScope == "this" || grantScope == "descendants" {
scopeIds = append(scopeIds, grantScope)
continue
}
scope, ok := s.RootModule().Resources[grantScope]
if !ok {
return fmt.Errorf("scope resource not found: %s", grantScope)
}
scopeId := scope.Primary.ID
if scopeId == "" {
return fmt.Errorf("scope resource ID not set")
}
scopeIds = append(scopeIds, scopeId)
}
md := testProvider.Meta().(*metaData)
rolesClient := roles.NewClient(md.client)
rr, err := rolesClient.Read(context.Background(), id)
if err != nil {
return fmt.Errorf("Got an error when reading role %q: %v", id, err)
}
// for every grant scope set on the role in the state, ensure each role
// in boundary has the same setings
if len(rr.Item.GrantScopeIds) == 0 {
return fmt.Errorf("no grant scope ids found in boundary")
}
for _, stateGrantScopeId := range rr.Item.GrantScopeIds {
ok := false
for _, gotScopeId := range scopeIds {
if gotScopeId == stateGrantScopeId {
ok = true
}
}
if !ok {
return fmt.Errorf("grant scope id in state not set in boundary: %s", stateGrantScopeId)
}
}
return nil
}
}
+4 -4
View File
@@ -189,7 +189,7 @@ resource "boundary_role" "with_grants" {
func TestAccRoleToOrgToProject(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...)
defer tc.Shutdown()
t.Cleanup(tc.Shutdown)
url := tc.ApiAddrs()[0]
var provider *schema.Provider
@@ -243,7 +243,7 @@ func TestAccRoleToOrgToProject(t *testing.T) {
func TestAccRoleWithGrants(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...)
defer tc.Shutdown()
t.Cleanup(tc.Shutdown)
url := tc.ApiAddrs()[0]
var provider *schema.Provider
@@ -302,7 +302,7 @@ func TestAccRoleWithGrants(t *testing.T) {
func TestAccRoleWithPrincipals(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...)
defer tc.Shutdown()
t.Cleanup(tc.Shutdown)
url := tc.ApiAddrs()[0]
var provider *schema.Provider
@@ -365,7 +365,7 @@ func TestAccRoleWithPrincipals(t *testing.T) {
func TestAccRoleWithGroups(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...)
defer tc.Shutdown()
t.Cleanup(tc.Shutdown)
url := tc.ApiAddrs()[0]
var provider *schema.Provider
@@ -0,0 +1,164 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package provider
import (
"context"
"fmt"
"net/http"
"strings"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/scopes"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (
policyIdKey = "policy_id"
storagePolicyPrefix = "pst_"
)
func resourceScopePolicyAttachment() *schema.Resource {
return &schema.Resource{
CreateContext: resourceScopePolicyAttachmentCreate,
ReadWithoutTimeout: resourceScopePolicyAttachmentRead,
DeleteWithoutTimeout: resourceScopePolicyAttachmentDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Schema: map[string]*schema.Schema{
ScopeIdKey: {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
policyIdKey: {
Type: schema.TypeString,
ForceNew: true,
Required: true,
},
},
}
}
func resourceScopePolicyAttachmentCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
scp := scopes.NewClient(md.client)
opts := []scopes.Option{scopes.WithAutomaticVersioning(true)}
var scopeId string
if scopeIdVal, ok := d.GetOk(ScopeIdKey); ok {
scopeId = scopeIdVal.(string)
} else {
return diag.Errorf("no scope ID provided")
}
if err := d.Set(ScopeIdKey, scopeId); err != nil {
return diag.FromErr(err)
}
var policyId string
if policyIdVal, ok := d.GetOk(policyIdKey); ok {
policyId = policyIdVal.(string)
} else {
return diag.Errorf("no policy ID provided")
}
// other policy types may be added here and in other switches with this file
switch {
case strings.HasPrefix(policyId, storagePolicyPrefix):
if _, err := scp.AttachStoragePolicy(ctx, scopeId, 0, policyId, opts...); err != nil {
return diag.FromErr(err)
}
default:
return diag.Errorf("unknown policy type provided.")
}
if err := d.Set(policyIdKey, policyId); err != nil {
return diag.FromErr(err)
}
d.SetId(fmt.Sprintf("%s:%s", policyId, scopeId))
return nil
}
func resourceScopePolicyAttachmentRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
scp := scopes.NewClient(md.client)
var scopeId string
if scopeIdVal, ok := d.GetOk(ScopeIdKey); ok {
scopeId = scopeIdVal.(string)
} else {
return diag.Errorf("no scope ID provided")
}
var policyId string
if policyIdVal, ok := d.GetOk(policyIdKey); ok {
policyId = policyIdVal.(string)
} else {
return diag.Errorf("no policy ID provided")
}
s, err := scp.Read(ctx, scopeId)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
// the scope is gone, destroy this resource
d.SetId("")
return nil
}
return diag.Errorf("error reading scope: %v", err)
}
if s == nil {
return diag.Errorf("scope nil after read")
}
switch {
case strings.HasPrefix(policyId, storagePolicyPrefix):
if policyId != s.GetItem().StoragePolicyId {
// this policy is no longer attached to the scope, destroy this resource
d.SetId("")
return nil
}
default:
return diag.Errorf("unknown policy type provided.")
}
return nil
}
func resourceScopePolicyAttachmentDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
scp := scopes.NewClient(md.client)
opts := []scopes.Option{scopes.WithAutomaticVersioning(true)}
var scopeId string
if scopeIdVal, ok := d.GetOk(ScopeIdKey); ok {
scopeId = scopeIdVal.(string)
} else {
return diag.Errorf("no scope ID provided")
}
var policyId string
if policyIdVal, ok := d.GetOk(policyIdKey); ok {
policyId = policyIdVal.(string)
} else {
return diag.Errorf("no policy ID provided")
}
switch {
case strings.HasPrefix(policyId, storagePolicyPrefix):
if _, err := scp.DetachStoragePolicy(ctx, scopeId, 0, opts...); err != nil {
return diag.FromErr(err)
}
default:
return diag.Errorf("unknown policy type provided.")
}
return nil
}
+4 -4
View File
@@ -33,7 +33,7 @@ resource "boundary_scope" "org1" {
resource "boundary_role" "org1_admin" {
scope_id = boundary_scope.global.id
grant_scope_id = boundary_scope.org1.id
grant_scope_ids = [boundary_scope.org1.id]
grant_strings = ["ids=*;type=*;actions=*"]
principal_ids = ["u_auth"]
}
@@ -49,7 +49,7 @@ resource "boundary_scope" "proj1" {
resource "boundary_role" "proj1_admin" {
scope_id = boundary_scope.org1.id
grant_scope_id = boundary_scope.proj1.id
grant_scope_ids = [boundary_scope.proj1.id]
grant_strings = ["ids=*;type=*;actions=*"]
principal_ids = ["u_auth"]
}
@@ -65,7 +65,7 @@ resource "boundary_scope" "proj1" {
resource "boundary_role" "proj1_admin" {
scope_id = boundary_scope.org1.id
grant_scope_id = boundary_scope.proj1.id
grant_scope_ids = [boundary_scope.proj1.id]
grant_strings = ["ids=*;type=*;actions=*"]
principal_ids = ["u_auth"]
}
@@ -80,7 +80,7 @@ resource "boundary_scope" "proj2" {
resource "boundary_role" "proj2_admin" {
scope_id = boundary_scope.org1.id
grant_scope_id = boundary_scope.proj2.id
grant_scope_ids = [boundary_scope.proj2.id]
grant_strings = ["ids=*;type=*;actions=*"]
principal_ids = ["u_auth"]
}