> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# PostgreSQL Instance IP Assignment Set To Private

### More Info:

Instance addresses can be public IP or private IP. Public IP means that the instance isaccessible through the public internet. In contrast, instances using only private IP arenot accessible through the public internet, but are accessible through a Virtual PrivateCloud

### Risk Level

Medium

### Address

Reliability, Security

### Compliance Standards

* CIS GCP
* CIS GCP 2.0.0

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        To allow public (external) access to a Cloud SQL for PostgreSQL instance in GCP using the Console, you need to **add a public IP** (you can keep the private IP as well if needed).

        ### Step-by-step in GCP Console

        1. **Go to Cloud SQL**
           * In the Google Cloud Console, go to:\
             `Navigation menu → Databases → SQL`
           * Click on your **PostgreSQL** instance.

        2. **Open the Connections settings**
           * In the instance page, click the **Edit** button at the top.
           * In the left or central tabs, find and click **Connections**.

        3. **Enable Public IP**
           * Scroll to the **Connectivity** or **IP addresses** section.
           * Under **Public IP**, check **Assign a public IP address** (or **Add network / Add public IP** depending on UI version).
           * The Console will show that a public IP will be assigned on save.

        4. **Configure Authorized Networks (Firewall for DB)**
           * Still under **Public IP**, find **Authorized networks**.
           * Click **Add Network**.
           * Enter:
             * **Name:** A label for the client/network (e.g., `office-network` or `dev-laptop`).
             * **Network:** The IP or CIDR that should be allowed (e.g., `203.0.113.10/32` for a single IP).
           * Repeat for all client IPs that need access.
           * Avoid `0.0.0.0/0` unless this is a controlled test environment and you fully understand the risk.

        5. **Save changes**
           * Scroll down and click **Save**.
           * Wait for the instance to finish updating (status changes back to **RUNNABLE**).

        6. **Get the public IP and connect**
           * In the instance **Overview** page, under **Connect to this instance** or **Instance IP addresses**, note the **Public IP address**.
           * Use this host in your PostgreSQL client connection string:
             * Host: the public IP
             * Port: default `5432` unless you changed it
             * User/password / database as configured.

        7. **(Optional) Keep or remove Private IP**
           * If you no longer want private-only access:
             * Go back to **Edit → Connections**.
             * Under **Private IP**, uncheck / remove private IP assignment (if your design allows).
             * **Save** again.

        This remediates the configuration from “private-only” to “private + public” (or public-only) access using the GCP Console.
      </Accordion>

      <Accordion title="Using CLI">
        To remediate “PostgreSQL Instance IP Assignment Set To Private” in GCP (i.e., enable a public IPv4 address) via gcloud, do the following:

        ***

        ### 1. Make sure you have the right project and auth

        ```bash theme={null}
        # Authenticate
        gcloud auth login

        # Set the correct project
        gcloud config set project YOUR_PROJECT_ID
        ```

        ***

        ### 2. Check current IP configuration of the instance

        ```bash theme={null}
        gcloud sql instances describe INSTANCE_NAME \
          --format="get(ipAddresses)"
        ```

        Confirm it only has `PRIVATE` and no `PRIMARY` / `PUBLIC` IPv4.

        ***

        ### 3. (Optional but recommended) Define authorized networks

        Decide which client IPs should be allowed to connect to the public IP.

        Example: allow only one office IP and one VPN IP:

        ```bash theme={null}
        AUTHORIZED_NETWORKS="Office=203.0.113.5/32,VPN=198.51.100.10/32"
        ```

        ***

        ### 4. Enable public IPv4 on the instance

        Use `gcloud sql instances patch` with `--assign-ip`. You can optionally add authorized networks at the same time.

        ```bash theme={null}
        gcloud sql instances patch INSTANCE_NAME \
          --assign-ip \
          --authorized-networks="${AUTHORIZED_NETWORKS}"
        ```

        Notes:

        * `--assign-ip` adds a public IPv4 address (keeps private IP if already enabled).
        * If you don’t want to set authorized networks now, just omit the flag and add them later.

        ***

        ### 5. Verify that a public IP was assigned

        ```bash theme={null}
        gcloud sql instances describe INSTANCE_NAME \
          --format="json(ipAddresses)"
        ```

        You should now see an entry like:

        ```json theme={null}
        "ipAddresses": [
          {
            "type": "PRIMARY",
            "ipAddress": "X.X.X.X"
          },
          {
            "type": "PRIVATE",
            "ipAddress": "10.x.x.x"
          }
        ]
        ```

        ***

        ### 6. (Optional) Adjust or add authorized networks later

        To update the allowed IP ranges:

        ```bash theme={null}
        gcloud sql instances patch INSTANCE_NAME \
          --authorized-networks="Office=203.0.113.5/32,VPN=198.51.100.10/32,Home=203.0.113.20/32"
        ```

        This overwrites the existing list with the one you provide.

        ***

        These commands will change the instance from “private-only” to having a public IPv4 endpoint while retaining the private IP if it was already configured.
      </Accordion>

      <Accordion title="Using Python">
        Below is how to change a Cloud SQL for PostgreSQL instance so it has a *public* IP (in addition to or instead of private IP) using Python.

        ***

        ### 1. Prerequisites

        1. Cloud SQL Admin API must be enabled:
           * [https://console.cloud.google.com/flows/enableapi?apiid=sqladmin.googleapis.com](https://console.cloud.google.com/flows/enableapi?apiid=sqladmin.googleapis.com)

        2. Authentication:
           * Use a service account with the `roles/cloudsql.admin` role.
           * Set `GOOGLE_APPLICATION_CREDENTIALS` to point to its JSON key, or run this from an environment with default credentials (e.g., Cloud Shell, Cloud Run with attached service account).

        3. Install libraries:

        ```bash theme={null}
        pip install google-api-python-client google-auth google-auth-httplib2
        ```

        ***

        ### 2. Python code to add a public IP

        This example:

        * Adds a public IP to an existing PostgreSQL instance.
        * Keeps existing private IP settings intact (if any).
        * Optionally restricts access with `authorizedNetworks`.

        Replace:

        * `PROJECT_ID` with your project ID
        * `INSTANCE_NAME` with your Cloud SQL instance name
        * `NETWORK_CIDR` with your allowed CIDR (or remove `authorizedNetworks` block if not needed)

        ```python theme={null}
        from googleapiclient.discovery import build
        from googleapiclient.errors import HttpError
        from google.oauth2 import service_account
        import time

        # ---- CONFIGURE THESE ----
        PROJECT_ID = "your-gcp-project-id"
        INSTANCE_NAME = "your-postgres-instance-name"
        SERVICE_ACCOUNT_KEY = "path/to/service-account.json"  # or use default creds
        NETWORK_CIDR = "203.0.113.0/24"  # example; change to your IP/CIDR
        # -------------------------

        def wait_for_operation(service, project, operation_name):
            while True:
                op = service.operations().get(
                    project=project,
                    operation=operation_name
                ).execute()

                if op.get("status") == "DONE":
                    if "error" in op:
                        raise RuntimeError(f"Operation error: {op['error']}")
                    break
                time.sleep(5)


        def main():
            # Use service account; or use google.auth.default() if running on GCP
            creds = service_account.Credentials.from_service_account_file(
                SERVICE_ACCOUNT_KEY,
                scopes=["https://www.googleapis.com/auth/cloud-platform"],
            )

            service = build("sqladmin", "v1beta4", credentials=creds, cache_discovery=False)

            try:
                # Get current instance config
                instance = service.instances().get(
                    project=PROJECT_ID,
                    instance=INSTANCE_NAME
                ).execute()

                settings = instance.get("settings", {})
                ip_config = settings.get("ipConfiguration", {})

                # Ensure public IP is enabled
                ip_config["ipv4Enabled"] = True

                # OPTIONAL: restrict access with authorized networks
                # If you already have authorizedNetworks, append instead of overwrite.
                ip_config["authorizedNetworks"] = [
                    {
                        "name": "allowed-office-network",
                        "value": NETWORK_CIDR,
                    }
                ]

                settings["ipConfiguration"] = ip_config

                body = {
                    "settings": settings
                }

                # Patch instance
                op = service.instances().patch(
                    project=PROJECT_ID,
                    instance=INSTANCE_NAME,
                    body=body
                ).execute()

                print(f"Patch operation started: {op['name']}")
                wait_for_operation(service, PROJECT_ID, op["name"])
                print("Instance updated. Public IP should now be assigned/enabled.")

            except HttpError as e:
                print(f"API error: {e}")
            except Exception as e:
                print(f"Error: {e}")


        if __name__ == "__main__":
            main()
        ```

        ***

        ### 3. Notes / Variations

        * **Keep both private and public IP**:\
          The code above leaves any existing `privateNetwork` and `pscConfig` untouched; it just enables `ipv4Enabled`. That gives you dual (private + public) connectivity.

        * **Remove public IP later (if needed)**:
          Set `ip_config["ipv4Enabled"] = False` and patch again.

        * **No network restriction**:
          If you omit `authorizedNetworks`, any IP can attempt to connect (still needs DB auth). For better security, always define `authorizedNetworks`.

        This is the standard remediation path if your security policy requires a publicly reachable PostgreSQL Cloud SQL instance instead of only private IP.
      </Accordion>

      <Accordion title="Using Terraform">
        ```hcl theme={null}
        resource "google_sql_database_instance" "POSTGRES_INSTANCE" {
          name             = "POSTGRES_INSTANCE_NAME"          # replace with your instance name
          database_version = "POSTGRES_14"                     # replace with your required version
          region           = "GCP_REGION"                      # replace with the region (e.g. us-central1)

          settings {
            tier = "DB_TIER"                                   # e.g. db-custom-2-7680

            ip_configuration {
              # Disable public IP
              ipv4_enabled    = false

              # Attach to a VPC for private IP
              private_network = google_compute_network.VPC.self_link
              # or use: "projects/PROJECT_ID/global/networks/VPC_NETWORK_NAME"
            }
          }
        }

        resource "google_compute_network" "VPC" {
          name = "VPC_NETWORK_NAME"                            # replace or reference existing VPC
        }

        resource "google_compute_global_address" "SQL_PRIVATE_SERVICE_RANGE" {
          name          = "SQL_PRIVATE_SERVICE_RANGE_NAME"     # replace with a unique name
          purpose       = "VPC_PEERING"
          address_type  = "INTERNAL"
          prefix_length = 16
          network       = google_compute_network.VPC.id
        }

        resource "google_service_networking_connection" "SQL_VPC_PEERING" {
          network                 = google_compute_network.VPC.id
          service                 = "servicenetworking.googleapis.com"
          reserved_peering_ranges = [google_compute_global_address.SQL_PRIVATE_SERVICE_RANGE.name]
        }
        ```

        Changing an existing Cloud SQL instance from public IP to private IP (`private_network` plus `ipv4_enabled = false`) can force replacement of the instance, which may cause downtime; review the `terraform plan` carefully before applying.

        For verification, `terraform plan` should show the `google_sql_database_instance` gaining `settings.ip_configuration.private_network` and `ipv4_enabled = false`, and (for an existing public-only instance) it may show the instance being replaced along with creation of the networking/peering resources if they are new.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://cloud.google.com/sql/docs/postgres/configure-private-ip](https://cloud.google.com/sql/docs/postgres/configure-private-ip)
