Skip to content

PostgreSQL backend does not properly respect schema_name configuration parameter #29034

@caseyandgina

Description

@caseyandgina

https://www.terraform.io/docs/language/settings/backends/pg.html#schema_name

I am using the following backend configuration:

terraform {
        backend "pg" {
                conn_str = "postgres://app_terraform:<password>@<host>/dba?sslmode=disable"
                schema_name = "terraform"
                skip_schema_creation = true
        }
}

I have created the schema as the database owner, using:

create schema "terraform" authorization "app_terraform";

...which sets the app_terraform user as the owner of the terraform schema, so that it can create whatever it wants in it. However, when I terraform init, I get the following error:

│ Error: pq: permission denied for schema public

Looking in the PostgreSQL log, this is because Terraform is explicitly trying to create a sequence in the public schema instead, which I do not permit:

2021-06-25 00:09:35.745 UTC,"app_terraform","dba",365766,"10.124.250.228:54729",60d51ebf.594c6,3,"CREATE SEQUENCE",2021-06-25 00:09:35 UTC,5/54951,0,ERROR,42501,"permission denied for schema public",,,,,,"CREATE SEQUENCE IF NOT EXISTS public.global_states_id_seq AS bigint",,,"","client backend"

It should use the schema_name specified in the backend configuration instead of "public" in the above statement. It's worth noting that if it is able to create the sequence in the public schema, it goes on to create the table that depends on the sequence in the schema specified in the configuration.

Also, the following from the documentation indicates a misunderstanding of how permissions work in PostgreSQL:

skip_index_creation - If set to true, the Postgres index must already exist. Terraform won't try to create the index. Useful when the Postgres user does not have "create index" permission on the database.

One cannot separately grant/revoke create table and create index. Either the user is able to create (anything) in the target schema, or it is not. Also, looking at the table that Terraform creates, there is no index aside from the ones required by the table's primary key and unique constraint definition. The table will allow duplicate name values to exist if the unique index is not added. So I believe this should be combined with the skip_table_creation configuration parameter.

Terraform attempts execute the following SQL statements:

CREATE SEQUENCE IF NOT EXISTS public.global_states_id_seq AS bigint;
CREATE TABLE IF NOT EXISTS "<schema_name>".states (
                        id bigint NOT NULL DEFAULT nextval('public.global_states_id_seq') PRIMARY KEY,
                        name text,
                        data text
                        )
CREATE UNIQUE INDEX IF NOT EXISTS states_by_name ON ""terraform"".states (name);

This can be simplified into a single statement, which makes it easier to keep everything together in one schema:

create table if not exists "<schema_name>".states (
	id bigserial not null,
	name text,
	data text,
	primary key (id),
	unique (name)
)

This will result in the sequence being named states_id_seq instead of global_states_id_seq, and the index being named states_name_key instead of states_by_name, but if the table already exists as created by the old method, it will not make any changes since a table of that name already exists.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions