Add the postgresql_schema_policy resource. This is a WIP due to

issues with cycles when an object is destroyed.
This commit is contained in:
Sean Chittenden 2016-12-16 18:00:54 -08:00
parent de6dcbd8cd
commit ebc81727da
No known key found for this signature in database
GPG Key ID: 4EBC9DC16C2E5E16
9 changed files with 812 additions and 4 deletions

View File

@ -64,10 +64,11 @@ func Provider() terraform.ResourceProvider {
},
ResourcesMap: map[string]*schema.Resource{
"postgresql_database": resourcePostgreSQLDatabase(),
"postgresql_extension": resourcePostgreSQLExtension(),
"postgresql_schema": resourcePostgreSQLSchema(),
"postgresql_role": resourcePostgreSQLRole(),
"postgresql_database": resourcePostgreSQLDatabase(),
"postgresql_extension": resourcePostgreSQLExtension(),
"postgresql_schema": resourcePostgreSQLSchema(),
"postgresql_schema_policy": resourcePostgreSQLSchemaPolicy(),
"postgresql_role": resourcePostgreSQLRole(),
},
ConfigureFunc: providerConfigure,

View File

@ -0,0 +1,442 @@
package postgresql
import (
"bytes"
"database/sql"
"fmt"
"log"
"strings"
"github.com/hashicorp/errwrap"
uuid "github.com/hashicorp/go-uuid"
"github.com/hashicorp/terraform/helper/schema"
"github.com/lib/pq"
"github.com/sean-/pgacl"
)
const (
schemaPolicyCreateAttr = "create"
schemaPolicyCreateWithGrantAttr = "create_with_grant"
schemaPolicyRoleAttr = "role"
schemaPolicySchemaAttr = "schema"
schemaPolicyUsageAttr = "usage"
schemaPolicyUsageWithGrantAttr = "usage_with_grant"
// schemaPolicyRolesAttr = "roles"
// schemaPolicySchemasAttr = "schemas"
)
func resourcePostgreSQLSchemaPolicy() *schema.Resource {
return &schema.Resource{
Create: resourcePostgreSQLSchemaPolicyCreate,
Read: resourcePostgreSQLSchemaPolicyRead,
Update: resourcePostgreSQLSchemaPolicyUpdate,
Delete: resourcePostgreSQLSchemaPolicyDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
schemaPolicyCreateAttr: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If true, allow the specified ROLEs to CREATE new objects within the schema(s)",
ConflictsWith: []string{schemaPolicyCreateWithGrantAttr},
},
schemaPolicyCreateWithGrantAttr: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If true, allow the specified ROLEs to CREATE new objects within the schema(s) and GRANT the same CREATE privilege to different ROLEs",
ConflictsWith: []string{schemaPolicyCreateAttr},
},
// schemaPolicyRolesAttr: {
// Type: schema.TypeList,
// Elem: &schema.Schema{Type: schema.TypeString},
// Description: "List of ROLEs who will receive this policy",
// },
schemaPolicyRoleAttr: {
Type: schema.TypeString,
Required: true,
Description: "ROLE who will receive this policy",
},
schemaPolicySchemaAttr: {
Type: schema.TypeString,
Required: true,
Description: "Target SCHEMA who will have this policy applied to it",
},
schemaPolicyUsageAttr: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If true, allow the specified ROLEs to use objects within the schema(s)",
ConflictsWith: []string{schemaPolicyUsageWithGrantAttr},
},
schemaPolicyUsageWithGrantAttr: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If true, allow the specified ROLEs to use objects within the schema(s) and GRANT the same USAGE privilege to different ROLEs",
ConflictsWith: []string{schemaPolicyUsageAttr},
},
},
}
}
func resourcePostgreSQLSchemaPolicyCreate(d *schema.ResourceData, meta interface{}) error {
id, err := uuid.GenerateUUID()
if err != nil {
return errwrap.Wrapf("Unable to generate schema policy ID: {{err}}", err)
}
d.SetId(id)
acl := pgacl.Schema{}
role := d.Get(schemaPolicyRoleAttr).(string)
if strings.ToUpper(role) != "PUBLIC" {
role = pq.QuoteIdentifier(role)
}
acl.CreateGrant = d.Get(schemaPolicyCreateWithGrantAttr).(bool)
if acl.CreateGrant {
acl.Create = true
} else {
acl.Create = d.Get(schemaPolicyCreateAttr).(bool)
}
acl.UsageGrant = d.Get(schemaPolicyUsageWithGrantAttr).(bool)
if acl.UsageGrant {
acl.Usage = true
} else {
acl.Usage = d.Get(schemaPolicyUsageAttr).(bool)
}
schema := d.Get(schemaPolicySchemaAttr).(string)
queries := make([]string, 0, 2)
if acl.Create {
b := bytes.NewBufferString("GRANT CREATE ON SCHEMA ")
fmt.Fprintf(b, "%s TO %s", pq.QuoteIdentifier(schema), role)
if acl.CreateGrant {
fmt.Fprint(b, " WITH GRANT OPTION")
}
queries = append(queries, b.String())
}
if acl.Usage {
b := bytes.NewBufferString("GRANT USAGE ON SCHEMA ")
fmt.Fprintf(b, "%s TO %s", pq.QuoteIdentifier(schema), role)
if acl.UsageGrant {
fmt.Fprint(b, " WITH GRANT OPTION")
}
queries = append(queries, b.String())
}
c := meta.(*Client)
conn, err := c.Connect()
if err != nil {
return err
}
defer conn.Close()
txn, err := conn.Begin()
if err != nil {
return err
}
defer txn.Rollback()
for _, query := range queries {
_, err = txn.Query(query)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf("Error applying policy on schema (%+q): {{err}}", query), err)
}
}
if err := txn.Commit(); err != nil {
return errwrap.Wrapf("Error committing schema policy: {{err}}", err)
}
return resourcePostgreSQLSchemaPolicyRead(d, meta)
}
func resourcePostgreSQLSchemaPolicyDelete(d *schema.ResourceData, meta interface{}) error {
role := d.Get(schemaPolicyRoleAttr).(string)
schema := d.Get(schemaPolicySchemaAttr).(string)
acl := pgacl.Schema{}
if strings.ToUpper(role) != "PUBLIC" {
role = pq.QuoteIdentifier(role)
}
acl.CreateGrant = d.Get(schemaPolicyCreateWithGrantAttr).(bool)
if acl.CreateGrant {
acl.Create = true
} else {
acl.Create = d.Get(schemaPolicyCreateAttr).(bool)
}
acl.UsageGrant = d.Get(schemaPolicyUsageWithGrantAttr).(bool)
if acl.UsageGrant {
acl.Usage = true
} else {
acl.Usage = d.Get(schemaPolicyUsageAttr).(bool)
}
queries := make([]string, 0, 2)
switch {
case !acl.Create:
b := bytes.NewBufferString("REVOKE CREATE ON SCHEMA ")
fmt.Fprintf(b, "%s FROM %s", pq.QuoteIdentifier(schema), role)
queries = append(queries, b.String())
case acl.Create && !acl.CreateGrant:
b := bytes.NewBufferString("REVOKE GRANT OPTION FOR CREATE ON SCHEMA ")
fmt.Fprintf(b, "%s FROM %s", pq.QuoteIdentifier(schema), role)
queries = append(queries, b.String())
}
switch {
case !acl.Usage:
b := bytes.NewBufferString("REVOKE USAGE ON SCHEMA ")
fmt.Fprintf(b, "%s FROM %s", pq.QuoteIdentifier(schema), role)
queries = append(queries, b.String())
case acl.Usage && !acl.UsageGrant:
b := bytes.NewBufferString("REVOKE GRANT OPTION FOR USAGE ON SCHEMA ")
fmt.Fprintf(b, "%s FROM %s", pq.QuoteIdentifier(schema), role)
queries = append(queries, b.String())
}
c := meta.(*Client)
conn, err := c.Connect()
if err != nil {
return err
}
defer conn.Close()
txn, err := conn.Begin()
if err != nil {
return err
}
defer txn.Rollback()
for _, query := range queries {
_, err = txn.Query(query)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf("Error removing policy on schema (%+q): {{err}}", query), err)
}
}
txn.Commit()
d.SetId("")
return resourcePostgreSQLSchemaPolicyRead(d, meta)
}
func resourcePostgreSQLSchemaPolicyRead(d *schema.ResourceData, meta interface{}) error {
c := meta.(*Client)
conn, err := c.Connect()
if err != nil {
return err
}
defer conn.Close()
oraw, _ := d.GetChange(schemaPolicySchemaAttr)
o := oraw.(string)
var schemaName, schemaOwner, schemaACL string
err = conn.QueryRow("SELECT n.nspname, pg_catalog.pg_get_userbyid(n.nspowner), n.nspacl FROM pg_catalog.pg_namespace n WHERE n.nspname = $1", o).Scan(&schemaName, &schemaOwner, &schemaACL)
switch {
case err == sql.ErrNoRows:
log.Printf("[WARN] PostgreSQL schema (%s) not found", o)
d.SetId("")
return nil
case err != nil:
return errwrap.Wrapf("Error reading schema ACLs: {{err}}", err)
default:
acl, err := pgacl.NewSchema(schemaACL)
if err != nil {
return err
}
switch {
case acl.CreateGrant:
d.Set(schemaPolicyCreateWithGrantAttr, true)
d.Set(schemaPolicyCreateAttr, false)
case acl.Create:
d.Set(schemaPolicyCreateAttr, true)
d.Set(schemaPolicyCreateWithGrantAttr, false)
default:
d.Set(schemaPolicyCreateWithGrantAttr, false)
d.Set(schemaPolicyCreateAttr, false)
}
switch {
case acl.UsageGrant:
d.Set(schemaPolicyUsageWithGrantAttr, true)
d.Set(schemaPolicyUsageAttr, false)
case acl.Usage:
d.Set(schemaPolicyUsageAttr, true)
d.Set(schemaPolicyUsageWithGrantAttr, false)
default:
d.Set(schemaPolicyUsageWithGrantAttr, false)
d.Set(schemaPolicyUsageAttr, false)
}
d.Set(schemaPolicySchemaAttr, acl.Role)
d.Set(schemaPolicySchemaAttr, schemaName)
return nil
}
}
func resourcePostgreSQLSchemaPolicyUpdate(d *schema.ResourceData, meta interface{}) error {
c := meta.(*Client)
conn, err := c.Connect()
if err != nil {
return err
}
defer conn.Close()
txn, err := conn.Begin()
if err != nil {
return err
}
defer txn.Rollback()
if err := setSchemaPolicyCreate(txn, d); err != nil {
return err
}
if err := setSchemaPolicyUsage(txn, d); err != nil {
return err
}
txn.Commit()
return resourcePostgreSQLSchemaRead(d, meta)
}
func setSchemaPolicyCreate(txn *sql.Tx, d *schema.ResourceData) error {
if !d.HasChange(schemaPolicyCreateAttr) && !d.HasChange(schemaPolicyCreateWithGrantAttr) {
return nil
}
oldCreateRaw, newCreateRaw := d.GetChange(schemaPolicyCreateAttr)
oldCreate := oldCreateRaw.(bool)
newCreate := newCreateRaw.(bool)
oldGrantRaw, newGrantRaw := d.GetChange(schemaPolicyCreateWithGrantAttr)
oldGrant := oldGrantRaw.(bool)
newGrant := newGrantRaw.(bool)
var grant, revoke, withGrant bool
switch {
case oldCreate == newCreate:
// nothing changed
case oldCreate && !newCreate:
// Lost create privs
revoke = true
case !oldCreate && newCreate:
// Gaining create privs
grant = true
}
switch {
case newGrant == oldGrant:
// Nothing changed
case newGrant && !oldGrant, // Getting WITH GRANT OPTION priv
!newGrant && oldGrant: // Loosing WITH GRANT OPTION priv
withGrant = true
}
role := d.Get(schemaPolicyRoleAttr).(string)
if strings.ToUpper(role) != "PUBLIC" {
role = pq.QuoteIdentifier(role)
}
schema := d.Get(schemaPolicySchemaAttr).(string)
b := &bytes.Buffer{}
switch {
case grant:
b = bytes.NewBufferString("GRANT CREATE ON SCHEMA ")
fmt.Fprintf(b, "%s TO %s", pq.QuoteIdentifier(schema), role)
if withGrant {
fmt.Fprint(b, " WITH GRANT OPTION")
}
case revoke:
b = bytes.NewBufferString("REVOKE")
if withGrant {
fmt.Fprint(b, " GRANT OPTION FOR")
}
fmt.Fprintf(b, " CREATE ON SCHEMA %s FROM %s", pq.QuoteIdentifier(schema), role)
}
query := b.String()
if _, err := txn.Query(query); err != nil {
return errwrap.Wrapf("Error updating schema create privileges: {{err}}", err)
}
return nil
}
func setSchemaPolicyUsage(txn *sql.Tx, d *schema.ResourceData) error {
if !d.HasChange(schemaPolicyUsageAttr) && !d.HasChange(schemaPolicyUsageWithGrantAttr) {
return nil
}
oldUsageRaw, newUsageRaw := d.GetChange(schemaPolicyUsageAttr)
oldUsage := oldUsageRaw.(bool)
newUsage := newUsageRaw.(bool)
oldGrantRaw, newGrantRaw := d.GetChange(schemaPolicyUsageWithGrantAttr)
oldGrant := oldGrantRaw.(bool)
newGrant := newGrantRaw.(bool)
var grant, revoke, withGrant bool
switch {
case oldUsage == newUsage:
// nothing changed
case oldUsage && !newUsage:
// Lost usage privs
revoke = true
case !oldUsage && newUsage:
// Gaining usage privs
grant = true
}
switch {
case newGrant == oldGrant:
// Nothing changed
case newGrant && !oldGrant, // Getting WITH GRANT OPTION priv
!newGrant && oldGrant: // Loosing WITH GRANT OPTION priv
withGrant = true
}
role := d.Get(schemaPolicyRoleAttr).(string)
if strings.ToUpper(role) != "PUBLIC" {
role = pq.QuoteIdentifier(role)
}
schema := d.Get(schemaPolicySchemaAttr).(string)
b := &bytes.Buffer{}
switch {
case grant:
b = bytes.NewBufferString("GRANT USAGE ON SCHEMA ")
fmt.Fprintf(b, "%s TO %s", pq.QuoteIdentifier(schema), role)
if withGrant {
fmt.Fprint(b, " WITH GRANT OPTION")
}
case revoke:
b = bytes.NewBufferString("REVOKE")
if withGrant {
fmt.Fprint(b, " GRANT OPTION FOR")
}
fmt.Fprintf(b, " USAGE ON SCHEMA %s FROM %s", pq.QuoteIdentifier(schema), role)
}
query := b.String()
if _, err := txn.Query(query); err != nil {
return errwrap.Wrapf("Error updating schema usage privileges: {{err}}", err)
}
return nil
}

View File

@ -0,0 +1,159 @@
package postgresql
import (
"database/sql"
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccPostgreSQLSchemaPolicy_Basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckPostgreSQLSchemaPolicyDestroy,
Steps: []resource.TestStep{
{
Config: testAccPostgreSQLSchemaPolicyConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckPostgreSQLSchemaPolicyExists("postgresql_schema.test1", "foo"),
resource.TestCheckResourceAttr(
"postgresql_role.dba", "name", "dba"),
resource.TestCheckResourceAttr(
"postgresql_role.app1", "name", "app1"),
resource.TestCheckResourceAttr(
"postgresql_role.app2", "name", "app2"),
resource.TestCheckResourceAttr(
"postgresql_schema.foo", "name", "foo"),
resource.TestCheckResourceAttr(
"postgresql_schema.owner", "name", "dba"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_allow", "create", "false"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_allow", "create_with_grant", "true"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_allow", "usage", "false"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_allow", "usage_with_grant", "true"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_allow", "schema", "foo"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_allow", "role", "app1"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_deny", "schema", "foo"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_deny", "role", "app2"),
),
},
},
})
}
func testAccCheckPostgreSQLSchemaPolicyDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*Client)
for _, rs := range s.RootModule().Resources {
if rs.Type != "postgresql_schema" {
continue
}
exists, err := checkSchemaExists(client, rs.Primary.ID)
if err != nil {
return fmt.Errorf("Error checking schema %s", err)
}
if exists {
return fmt.Errorf("Schema still exists after destroy")
}
}
return nil
}
func testAccCheckPostgreSQLSchemaPolicyExists(n string, schemaName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Resource not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
actualSchemaName := rs.Primary.Attributes["name"]
if actualSchemaName != schemaName {
return fmt.Errorf("Wrong value for schema name expected %s got %s", schemaName, actualSchemaName)
}
client := testAccProvider.Meta().(*Client)
exists, err := checkSchemaExists(client, rs.Primary.ID)
if err != nil {
return fmt.Errorf("Error checking schema %s", err)
}
if !exists {
return fmt.Errorf("Schema not found")
}
return nil
}
}
func checkSchemaPolicyExists(client *Client, schemaName string) (bool, error) {
conn, err := client.Connect()
if err != nil {
return false, err
}
defer conn.Close()
var _rez string
err = conn.QueryRow("SELECT nspname FROM pg_catalog.pg_namespace WHERE nspname=$1", schemaName).Scan(&_rez)
switch {
case err == sql.ErrNoRows:
return false, nil
case err != nil:
return false, fmt.Errorf("Error reading info about schema: %s", err)
default:
return true, nil
}
}
var testAccPostgreSQLSchemaPolicyConfig = `
resource "postgresql_role" "dba" {
name = "dba"
}
resource "postgresql_role" "app1" {
name = "app1"
# depends_on = ["postgresql_schema_policy.foo_allow"]
}
resource "postgresql_role" "app2" {
name = "app2"
}
resource "postgresql_schema" "foo" {
name = "foo"
owner = "${postgresql_role.dba.name}"
}
resource "postgresql_schema_policy" "foo_allow" {
create_with_grant = true
usage_with_grant = true
schema = "${postgresql_schema.foo.name}"
role = "${postgresql_role.app1.name}"
}
resource "postgresql_schema_policy" "foo_deny" {
schema = "${postgresql_schema.foo.name}"
role = "${postgresql_role.app2.name}"
}
`

25
vendor/github.com/sean-/pgacl/LICENSE generated vendored Normal file
View File

@ -0,0 +1,25 @@
BSD 2-Clause License
Copyright (c) 2016, Sean Chittenden
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

7
vendor/github.com/sean-/pgacl/acl.go generated vendored Normal file
View File

@ -0,0 +1,7 @@
package pgacl
// ACL is a generic interface that all pgacl types must adhere to
type ACL interface {
// String creates a PostgreSQL compatible ACL string
String() string
}

89
vendor/github.com/sean-/pgacl/schema.go generated vendored Normal file
View File

@ -0,0 +1,89 @@
package pgacl
import (
"bytes"
"fmt"
"strings"
)
// Schema models the privileges of a schema
type Schema struct {
Role string
Create bool
CreateGrant bool
Usage bool
UsageGrant bool
}
const numSchemaOpts = 4
// NewSchema parses a PostgreSQL ACL string for a schema and returns a Schema
// object
func NewSchema(aclStr string) (Schema, error) {
acl := Schema{}
idx := strings.IndexByte(aclStr, '=')
if idx == -1 {
return Schema{}, fmt.Errorf("invalid aclStr format: %+q", aclStr)
}
acl.Role = aclStr[:idx]
aclLen := len(aclStr)
var i int
withGrant := func() bool {
if i+1 >= aclLen {
return false
}
if aclStr[i+1] == '*' {
i++
return true
}
return false
}
for i = idx + 1; i < aclLen; i++ {
switch aclStr[i] {
case 'C':
acl.Create = true
if withGrant() {
acl.CreateGrant = true
}
case 'U':
acl.Usage = true
if withGrant() {
acl.UsageGrant = true
}
default:
return Schema{}, fmt.Errorf("invalid byte %c in schema ACL at %d: %+q", aclStr[i], i, aclStr)
}
}
return acl, nil
}
// String creates a PostgreSQL native output for the ACLs that apply to a
// schema.
func (s Schema) String() string {
b := new(bytes.Buffer)
b.Grow(len(s.Role) + numSchemaOpts + 1)
fmt.Fprint(b, s.Role, "=")
if s.Usage {
fmt.Fprint(b, "U")
if s.UsageGrant {
fmt.Fprint(b, "*")
}
}
if s.Create {
fmt.Fprint(b, "C")
if s.CreateGrant {
fmt.Fprint(b, "*")
}
}
return b.String()
}

6
vendor/vendor.json vendored
View File

@ -2268,6 +2268,12 @@
"revision": "88132ecdd39da62f7c73c5a8e1a383d7da5e0e09",
"revisionTime": "2016-10-27T15:40:24Z"
},
{
"checksumSHA1": "fCtp8mJPTtEMkpDz8TgRtJzMYw0=",
"path": "github.com/sean-/pgacl",
"revision": "3d9f301f1bf3d5b590119b28132d2e8d5d1f1a62",
"revisionTime": "2016-12-15T16:51:43Z"
},
{
"checksumSHA1": "BqtlwAjgFuHsVVdnw+dGSe+CKLM=",
"path": "github.com/sethvargo/go-fastly",

View File

@ -0,0 +1,76 @@
---
layout: "postgresql"
page_title: "PostgreSQL: postgresql_schema_policy"
sidebar_current: "docs-postgresql-resource-postgresql_schema_policy"
description: |-
Manages the permissions of PostgreSQL schemas.
---
# postgresql\_schema\_policy
The ``postgresql_schema_policy`` resource applies the necessary SQL DCL
(`GRANT`s and `REVOKE`s) necessary to ensure access compliance to a particular
SCHEMA within a PostgreSQL database.
## Usage
```
resource "postgresql_role" "my_app" {
name = "my_app"
}
resource "postgresql_schema" "my_schema" {
name = "my_schema"
}
resource "postgresql_schema_policy" "my_schema" {
create = true
usage = true
schema = "${postgresql_schema.my_schema.name}"
role = "${postgresql_role.my_app.name}"
}
```
## Argument Reference
* `create` - (Optional) Should the specified ROLE have CREATE privileges to the specified SCHEMA.
* `create_with_grant` - (Optional) Should the specified ROLE have CREATE privileges to the specified SCHEMA and the ability to GRANT the CREATE privilege to other ROLEs.
* `usage` - (Optional) Should the specified ROLE have USAGE privileges to the specified SCHEMA.
* `usage_with_grant` - (Optional) Should the specified ROLE have USAGE privileges to the specified SCHEMA and the ability to GRANT the USAGE privilege to other ROLEs.
* `role` - (Required) The ROLE who is receiving the policy.
* `schema` - (Required) The SCHEMA that is the target of the policy.
## Import Example
`postgresql_schema_policy` supports importing resources. Supposing the
following Terraform:
```
resource "postgresql_schema" "public" {
name = "public"
}
resource "postgresql_schema_policy" "public" {
create = true
usage = true
schema = "${postgresql_schema.public.name}"
role = "${postgresql_role.my_app.name}"
}
```
It is possible to import a `postgresql_schema_policy` resource with the
following command:
```
$ terraform import postgresql_schema_policy.public public
```
Where `public` is the name of the schema in the PostgreSQL database and
`postgresql_schema_policy.public` is the name of the resource whose state will
be populated as a result of the command.

View File

@ -25,6 +25,9 @@
<li<%= sidebar_current("docs-postgresql-resource-postgresql_schema") %>>
<a href="/docs/providers/postgresql/r/postgresql_schema.html">postgresql_schema</a>
</li>
<li<%= sidebar_current("docs-postgresql-resource-postgresql_schema_policy") %>>
<a href="/docs/providers/postgresql/r/postgresql_schema_policy.html">postgresql_schema_policy</a>
</li>
</ul>
</li>
</ul>