The Problem

I am trying to setup Hashicorp vault and Postgres in Google Cloud.

I am using liquibase to manage the schema and when that does a migration, it retrieves a username/password from vault and then runs under that user to perform the migration.

However, the default postgres user, or any other user that tries to use that table can't and receives the ERROR: permission denied for relation.

If I understand correctly, the users are being created while logged into as the role of postgres. This all works locally but the google cloud stuff seems to be setup in a vastly different way.

Here are some outputs to see what the database is setup as:

                                                List of roles
            Role name             |                         Attributes                         |      Member of
 cloudsqladmin                    | Superuser, Create role, Create DB, 
Replication, Bypass RLS | {}
 cloudsqlagent                    | Create role, Create DB                                     
| {cloudsqlsuperuser}
 cloudsqlreplica                  | Replication                                                
| {}
 cloudsqlsuperuser                | Create role, Create DB                                     
| {}
 postgres                         | Create role, Create DB                                     
| {cloudsqlsuperuser}
 test                             | Create role, Create DB                                     
| {cloudsqlsuperuser}
 v-token-power-watc-p079t4r13s85w | Password valid until              
| {cloudsqlsuperuser}

                            List of relations
 Schema |         Name          | Type  |              Owner
 public | databasechangelog     | table | v-token-power-watc-p079t4r13s85w
 public | databasechangeloglock | table | v-token-power-watc-p079t4r13s85w
 public | test                  | table | v-token-power-watc-p079t4r13s85w

The vault creation SQL looks something like this:

CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; 
GRANT cloudsqlsuperuser to "{{name}}";"

I've tried playing with the roles in a number of ways but it seems all of the new roles that I create are always put into their own sandbox and can't play with any other roles. I'm at a lost at this point of exactly what to do next, it seems that no matter the grant options I can pass, it doens't help.

Current Questions

Is it that the owner needs to be the cloudsqlsuperuser group instead of the temp ownwer?

Is there a way to make that the default instead of having to make sure all my tables are created with the right owner?

Replicate with a local docker instance

Docker Command to start Postgres Database

docker run --rm --name database -v $(pwd)/setup.sql:/docker-entrypoint-initdb.d/setup.sql -e POSTGRES_USER=temp -e POSTGRES_PASSWORD=secret -e POSTGRES_DB=mydb postgres:9.6

Contents of setup.sql

ALTER ROLE postgres RENAME TO cloudsqladmin;
ALTER DATABASE mydb OWNER TO cloudsqlsuperuser;

Creating user under postgres simulating vault user creation

docker exec -ti database psql -U postgres -d mydb -c "CREATE ROLE testuser WITH LOGIN IN ROLE cloudsqlsuperuser"

Create test table from testuser

docker exec -ti database psql -U testuser -d mydb -c "CREATE TABLE test (col1 text)"

Try and select table demonstrating error

docker exec -ti database psql -U postgres -d mydb -c "SELECT * FROM test"
  • Yes, I know if I had superuser to the postgres role this just works. But Google SQL Cloud doesn't allow it!
    – Erik L
    Commented Jun 4, 2018 at 3:08

1 Answer 1


Short Summary

You have to run an REASSIGN OWNED BY "$VAULT_USERNAME" TO "cloudsqlsuperuser" after the table/sequence/function creation process to reassign back to a the common role.

Longer Answer

Postgres 9.6 CREATE TABLE will by default create the table under the user's role. Because the vault user is designed to be a temporary credential, we need to also make sure that the objects created under the temporary roles are reassigned back to a common role of some kind. In the specific case I outlined in Google Cloud, we are going to reassign back to cloudsqlsuperuser.

The one command I found to work is the REASSIGN OWNED BY current_user to "cloudsqlsuperuser" command that will then take all of the objects owned by that temporary user and assign back to that common role.

Bonus: liquibase config

I am using liquibase to do my migrations and this is in my change log to fix the permissions everytime we run a migration:

    <changeSet author="elindblom" id="fix-permissions" context="" logicalFilePath="fix-permissions" runAlways="true" runOrder="last">
        <sqlFile path="baselines/sql/fix-permissions.sql" splitStatements="false" relativeToChangelogFile="true" stripComments="false"/>
   ... rest of your change logs after ...

The SQL looks like this:

REASSIGN OWNED BY current_user TO "cloudsqlsuperuser";

The changeSet runs after everything comes to completion and runs every-time. The very important bits are the runAlways and runOrder elements.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.