diff --git a/postgresql/config.go b/postgresql/config.go index 2c7395f9..7b7a3df1 100644 --- a/postgresql/config.go +++ b/postgresql/config.go @@ -59,6 +59,7 @@ const ( fetureRoleEncryptedPass featureAdvisoryXactLock featureTransactionIsolation + featureSysPrivileges ) var ( @@ -154,6 +155,7 @@ var ( featureAdvisoryXactLock: semver.MustParseRange(">=9.1.0"), //Postgresql do not support transaction isolation in Role level featureTransactionIsolation: semver.MustParseRange("<1.0.0"), + featureSysPrivileges: semver.MustParseRange("<1.0.0"), } // Mapping of feature flags to versions @@ -266,6 +268,7 @@ var ( featureAdvisoryXactLock: semver.MustParseRange("<1.0.0"), featureTransactionIsolation: semver.MustParseRange(">=23.2.0"), + featureSysPrivileges: semver.MustParseRange(">=22.2.0"), } ) diff --git a/postgresql/helpers.go b/postgresql/helpers.go index 94f7d7d9..8ccf39d4 100644 --- a/postgresql/helpers.go +++ b/postgresql/helpers.go @@ -236,6 +236,7 @@ func sliceContainsStr(haystack []string, needle string) bool { // allowedPrivileges is the list of privileges allowed per object types in Postgres. // see: https://www.postgresql.org/docs/current/sql-grant.html var allowedPrivileges = map[string][]string{ + "system": {"ALL", "BACKUP", "CANCELQUERY", "CONTROLJOB", "CREATEDB", "CREATELOGIN", "CREATEROLE", "EXTERNALCONNECTION", "EXTERNALIOIMPLICITACCESS", "MODIFYCLUSTERSETTING", "MODIFYSQLCLUSTERSETTING", "NOSQLLOGIN", "REPLICATION", "RESTORE", "VIEWACTIVITY", "VIEWACTIVITYREDACTED", "VIEWCLUSTERMETADATA", "VIEWCLUSTERSETTING", "VIEWDEBUG", "VIEWJOB", "VIEWSYSTEMTABLE"}, "database": {"ALL", "CREATE", "CONNECT", "TEMPORARY", "BACKUP", "RESTORE", "ZONECONFIG"}, "table": {"ALL", "SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER", "DROP", "CHANGEFEED", "RESTORE", "ZONECONFIG"}, "sequence": {"ALL", "USAGE", "SELECT", "UPDATE", "CREATE", "DELETE", "INSERT", "ZONECONFIG"}, diff --git a/postgresql/resource_postgresql_grant.go b/postgresql/resource_postgresql_grant.go index f7685bde..0706a1b5 100644 --- a/postgresql/resource_postgresql_grant.go +++ b/postgresql/resource_postgresql_grant.go @@ -14,6 +14,7 @@ import ( ) var allowedObjectTypes = []string{ + "system", "database", "function", "procedure", @@ -255,6 +256,16 @@ func resourcePostgreSQLGrantDelete(db *DBConnection, d *schema.ResourceData) err return nil } +func readSystemRolePriviges(txn *sql.Tx, role string) error { + var query string + var privileges pq.ByteaArray + query = fmt.Sprintf(`with a as (show system grants for %s) select array_agg(privilege_type) from a`, role) + if err := txn.QueryRow(query).Scan(&privileges); err != nil { + return fmt.Errorf("could not read system privileges: %w", err) + } + return nil +} + func readDatabaseRolePriviges(txn *sql.Tx, db *DBConnection, d *schema.ResourceData, roleOID uint32, role string) error { dbName := d.Get("database").(string) var query string @@ -443,6 +454,8 @@ func readRolePrivileges(txn *sql.Tx, db *DBConnection, d *schema.ResourceData) e var rows *sql.Rows switch objectType { + case "system": + return readSystemRolePriviges(txn, role) case "database": return readDatabaseRolePriviges(txn, db, d, roleOID, role) @@ -547,6 +560,12 @@ func createGrantQuery(d *schema.ResourceData, privileges []string) string { var query string switch strings.ToUpper(d.Get("object_type").(string)) { + case "SYSTEM": + query = fmt.Sprintf( + "GRANT SYSTEM %s TO %s", + strings.Join(privileges, ","), + pq.QuoteIdentifier(d.Get("role").(string)), + ) case "DATABASE": query = fmt.Sprintf( "GRANT %s ON DATABASE %s TO %s", @@ -618,6 +637,11 @@ func createRevokeQuery(d *schema.ResourceData) string { var query string switch strings.ToUpper(d.Get("object_type").(string)) { + case "SYSTEM": + query = fmt.Sprintf( + "REVOKE SYSTEM ALL FROM %s", + pq.QuoteIdentifier(d.Get("role").(string)), + ) case "DATABASE": query = fmt.Sprintf( "REVOKE ALL PRIVILEGES ON DATABASE %s FROM %s", @@ -839,19 +863,25 @@ func getRolesToGrant(txn *sql.Tx, d *schema.ResourceData) ([]string, error) { func validateFeatureSupport(db *DBConnection, d *schema.ResourceData) error { if !db.featureSupported(featurePrivileges) { return fmt.Errorf( - "postgresql_grant resource is not supported for this Postgres version (%s)", + "postgresql_grant resource is not supported for this version (%s)", db.version, ) } if d.Get("object_type") == "procedure" && !db.featureSupported(featureProcedure) { return fmt.Errorf( - "object type PROCEDURE is not supported for this Postgres version (%s)", + "object type PROCEDURE is not supported for this version (%s)", db.version, ) } if d.Get("object_type") == "routine" && !db.featureSupported(featureRoutine) { return fmt.Errorf( - "object type ROUTINE is not supported for this Postgres version (%s)", + "object type ROUTINE is not supported for this version (%s)", + db.version, + ) + } + if d.Get("object_type") == "system" && !db.featureSupported(featureSysPrivileges) { + return fmt.Errorf( + "privelege type System is not supported for this version (%s)", db.version, ) }