♊️ GemiNews 🗞️
(dev)
🏡
📰 Articles
🏷️ Tags
🧠 Queries
📈 Graphs
☁️ Stats
💁🏻 Assistant
💬
🎙️
Demo 1: Embeddings + Recommendation
Demo 2: Bella RAGa
Demo 3: NewRetriever
Demo 4: Assistant function calling
Editing article
Title
Summary
Content
<h3><strong>Introduction</strong></h3><p><a href="https://cloud.google.com/alloydb#documentation">AlloyDB</a> is a fully managed PostgreSQL compatible database service for your most demanding enterprise workloads. AlloyDB combines the best of Google with PostgreSQL, for superior performance, scale, and availability.</p><p>Since AlloyDB is PostgreSQL compatible, you can use <a href="https://github.com/jackc/pgx/">pgxpool</a> and <a href="https://github.com/brettwooldridge/HikariCP/blob/dev/README.md">HikariCP</a> for connection pooling in “Go” and “Java” applications respectively.</p><p>There are two prominent ways to <strong>connect securely to AlloyDB:</strong></p><ul><li>AlloyDB Auth Proxy</li><li>AlloyDB Language connectors</li></ul><h4>AlloyDB Auth Proxy</h4><ul><li><strong>IAM-based connection authorization (AuthZ):</strong> The Auth Proxy uses the credentials and permissions of an IAM principal to authorize connections to AlloyDB instances.</li><li><strong>Secure, encrypted communication:</strong> The Auth Proxy automatically creates, uses, and maintains a TLS 1.3 connection using a 256-bit AES cipher between your client and an AlloyDB instance.</li></ul><h4>AlloyDB Language connectors</h4><p>AlloyDB connectors are the language specific libraries for connecting securely to your AlloyDB instances. Using an AlloyDB connector provides the following additional benefits (besides the ones provided by AlloyDB Auth Proxy) :</p><ul><li><strong>Convenience</strong>: removes the requirement to use and distribute SSL certificates, as well as manage firewalls or source/destination IP addresses. <strong>You also don’t need to manage a separate Auth proxy container or process.</strong></li><li>(optionally) <strong>IAM DB Authentication</strong>: provides support for <a href="https://github.com/GoogleCloudPlatform/alloydb-go-connector?tab=readme-ov-file#automatic-iam-database-authentication">AlloyDB’s automatic IAM DB AuthN</a> feature. That means <strong>you can configure service accounts to connect to database</strong>. For applications deployed on GKE you can use workload identity to authenticate to the backend AlloyDB database.</li></ul><p>AlloyDB Language connectors are available for Go, Java and Python at this time.</p><h3>Purpose</h3><p>If you’re deploying a Go application on GCE/GKE and want to streamline secure connections to your AlloyDB database, the AlloyDB Go connector with IAM authentication is the way to go.</p><p>In this post I will walk you through the process of configuring your application and AlloyDB Instance for using AlloyDB Go connector such that your application can use a service account to connect to AlloyDB database. You don’t need to configure any vault to store the DB user password, no need to store any keyfile for the service account.</p><p>We are considering a hypothetical Go application (<a href="https://github.com/bijeshos/go-postgresql-pgx-example/blob/main/main.go">example</a>) which will be deployed on GCE for this article.</p><h3>Assumptions</h3><ol><li>GCP Project is already created</li><li>VPC network exists for this project and has a subnet defined for GCE/GKE</li><li>AlloyDB, Service Networking, Compute APIs are enabled</li></ol><h3>Steps</h3><h4>Create a service account</h4><p>This is the service account which will be configured as AlloyDB user and will be used by application to connect to database.</p><pre>read -p "project_id: " PROJECT_ID<br>read -p "region: " REGION<br>read -p "serviceaccount: " SERVICEACCOUNT<br>gcloud iam service-accounts create ${SERVICEACCOUNT} --display-name="alloydb service-account" --project ${PROJECT_ID}</pre><h4>Add roles to the service account</h4><p>As per <a href="https://cloud.google.com/alloydb/docs/manage-iam-authn#role,">https://cloud.google.com/alloydb/docs/manage-iam-authn#role,</a> we need to assign roles alloydb.client, alloydb.databaseUser and serviceusage.serviceUsageConsumer to the service account.</p><pre>gcloud projects add-iam-policy-binding ${PROJECT_ID} --member='serviceAccount:${SERVICEACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com' --role='roles/alloydb.client'<br>gcloud projects add-iam-policy-binding ${PROJECT_ID} --member='serviceAccount:${SERVICEACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com' --role='roles/alloydb.databaseUser'<br>gcloud projects add-iam-policy-binding ${PROJECT_ID} --member='serviceAccount:${SERVICEACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com' --role='roles/serviceusage.serviceUsageConsumer'</pre><h4>Create private service access</h4><p>Use Private Services Access to connect to AlloyDB service.</p><p>Private services access requires you to first allocate an internal IPv4 address range and then create a private connection</p><pre>read -p "region : " REGION<br>read -p "projectid : " PROJECT_ID<br>read -p "postgres_password: " PASSWORD<br>read -p "vpc network: " VPC_NETWORK<br><br>gcloud compute addresses create alloydbpsa \<br> --global \<br> --purpose=VPC_PEERING \<br> --prefix-length=16 \<br> --description="Private service access" \<br> --network=$VPC_NETWORK \<br> --project ${PROJECT_ID}</pre><h4>Create VPC private connection to alloydb service</h4><p>Private connection enables private access for AlloyDB Instances</p><pre>gcloud services vpc-peerings connect \<br> --service=servicenetworking.googleapis.com \<br> --ranges=alloydbpsa \<br> --network=$VPC_NETWORK \<br>--project ${PROJECT_ID}</pre><h4>Create AlloyDB Cluster and Primary Instance</h4><p>Below commands will create an AlloyDB Cluster and Instance. Please update the cluster and Instance names as per requirements.</p><pre>read -p "region : " REGION<br>read -p "projectid : " PROJECT_ID<br>read -p "postgres_password: " PASSWORD<br>read -p "vpc network: " VPC_NETWORK<br>gcloud alloydb clusters create alloydb-cls-$(date +%d%m%Y) \<br>--region=${REGION} --password=$PASSWORD --network=${VPC_NETWORK} \<br>--project=${PROJECT_ID}<br><br>gcloud beta alloydb instances create alloydb-ins-primary-$(date +%d%m%Y) \<br>--cluster=alloydb-cls-$(date +%d%m%Y) --region=${REGION} \<br>--instance-type=PRIMARY --cpu-count=2 \<br>--database-flags=alloydb.iam_authentication=on,alloydb.enable_auto_explain=on \<br>--availability-type=ZONAL --project=${PROJECT_ID}</pre><p>Notice that AlloyDB Instance has flag <strong>alloydb.iam_authentication</strong> set to on. This flag enables IAM authentication on an AlloyDB instance. If you already have an AlloyDB Instance, you can use below command to enable this flag.</p><pre>gcloud alloydb instances update $INSTANCE --cluster=$CLUSTER \<br> --region=$REGION --database-flags=alloydb.iam_authentication=on</pre><h4>Create a AlloyDB user with name same as the service account</h4><p>Username must be a same as the service account leaving the suffix “.gserviceaccount.com” and authentication type must be “IAM_BASED”.</p><pre>read -p "serviceaccount: " SERVICEACCOUNT<br>gcloud alloydb users create ${SERVICEACCOUNT}@${PROJECT_ID}.iam \<br>--cluster=alloydb-cls-$(date +%d%m%Y) --type=IAM_BASED \<br>--region=${REGION} --project=${PROJECT_ID}</pre><h4>Create Application schema and grant appropriate roles</h4><p>Connect to AlloyDB database postgres using a BUILTIN user (postgres) to create “application” database and grant appropriate roles to AlloyDB IAM user on “application” database.</p><p>To connect you may use AlloyDB SQL studio or psql.</p><pre>create database application;<br>---replace the ${SERVICEACCOUNT}@${PROJECT_ID}.iam with actual SA<br>grant all privileges on database application to "${SERVICEACCOUNT}@${PROJECT_ID}.iam";</pre><h4>Create GCE Instance</h4><p>Create GCE spot Instance (experimentation purposes only) where our application will be deployed.</p><pre>read -p "GCE subnet:" GCE_SUBNET<br>gcloud compute instances create instance-$(date +%d%m%Y) \<br>--project=${PROJECT_ID} --zone=${REGION}-a --machine-type=e2-medium \<br>--network-interface=network-tier=PREMIUM,stack-type=IPV4_ONLY,subnet=$GCE_SUBNET \<br>--provisioning-model=SPOT --service-account=${SERVICEACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com \<br>--scopes=https://www.googleapis.com/auth/cloud-platform \<br>--create-disk=auto-delete=yes,boot=yes,device-name=instance-$(date +%d%m%Y)-230433,image=projects/debian-cloud/global/images/debian-12-bookworm-v20240213,mode=rw,size=10,type=projects/${PROJECT_ID}/zones/${REGION}-a/diskTypes/pd-balanced \<br>--no-shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring \<br>--labels=goog-ec-src=vm_add-gcloud --reservation-affinity=any \<br>--preemptible --metadata=startup-script='#! /bin/bash<br> apt update -y<br> apt -y install golang unzip git'</pre><p>Notice that we bind the service account (DB User Service Account) that we created earlier to the GCE VM.</p><p>Now any process running on GCE VM can use that service account to authenticate to allowed APIs using assigned roles.</p><h4>Connecting to postgres using pgx pool (no connector)</h4><p>To make a connection to your database you would typically be using a function such as below. This uses <a href="https://pkg.go.dev/github.com/jackc/pgx/v5/pgxpool#pkg-overview">pgxpool package</a> to create a connection pool.</p><pre>func connectPostgres() (*pgxpool.Pool, error) {<br> ctx := context.Background()<br> var (<br> dsn string<br> dbname = os.Getenv("DBNAME")<br> user = os.Getenv("DBUSER")<br> host = os.Getenv("PGHOSTNAME")<br> password = os.Getenv("PGPASSWORD")<br> err error<br> )<br><br> dsn = fmt.Sprintf(<br> //user=jack password=secret host=pg.example.com port=5432 dbname=mydb sslmode=verify-ca pool_max_conns=10<br> // connection instead.<br> "user=%s password=%s dbname=%s sslmode=disable host=%s",<br> user, password, dbname, host,<br> )<br> config, err := pgxpool.ParseConfig(dsn)<br> if err != nil {<br> return nil, fmt.Errorf("failed to parse pgx config: %v", err)<br> }<br> // Establish the connection.<br> pool, connErr := pgxpool.NewWithConfig(ctx, config)<br> if connErr != nil {<br> return nil, fmt.Errorf("failed to connect: %s", connErr)<br> }<br> return pool, nil<br><br>}</pre><p>This requires you to define environment variables DBNAME, DBUSER, PGHOSTNAME and PGPASSWORD.</p><p>If you want to encrypt the data in transit, you have to configure sslmode and configure TLS certificates to encrypt the data in transit. You will need to manage the certificates on the application host.</p><h4>Connecting to postgres using pgx pool and Go Connector</h4><p>Update the definition of connectPostgres() in your application to the below.</p><pre>func connectPostgres() (*pgxpool.Pool, error) {<br> ctx := context.Background()<br>// export DBNAME=application<br>// export DBUSER=${SERVICEACCOUNT}@${PROJECT_ID}.iam<br>// export INSTURI=projects/${PROJECT_ID}/locations/${REGION}/clusters/alloydb-cls--$(date +%d%m%Y)/instances/alloydb-ins-primary--$(date +%d%m%Y)<br> var (<br> dsn string<br> dbname = os.Getenv("DBNAME")<br> user = os.Getenv("DBUSER")<br> instURI = os.Getenv("INSTURI")<br> )<br>// A Dialer can be configured to connect to an AlloyDB instance <br>// using automatic IAM database authentication with the WithIAMAuthN Option.<br> d, err := alloydbconn.NewDialer(ctx, alloydbconn.WithIAMAuthN())<br>if err != nil {<br> return nil, fmt.Errorf("failed to init Dialer: %v", err)<br> }<br> dsn = fmt.Sprintf(<br> // sslmode is disabled, because the Dialer will handle the SSL<br> // connection instead.<br> "user=%s dbname=%s sslmode=disable",<br> user, dbname,<br> )<br> config, err := pgxpool.ParseConfig(dsn)<br> if err != nil {<br> return nil, fmt.Errorf("failed to parse pgx config: %v", err)<br> }<br> // Tell pgx to use alloydbconn.Dialer to connect to the instance.<br> config.ConnConfig.DialFunc = func(ctx context.Context, _ string, _ string) (net.Conn, error) {<br> return d.Dial(ctx, instURI)<br> }<br> // Establish the connection.<br> pool, connErr := pgxpool.NewWithConfig(ctx, config)<br> if connErr != nil {<br> return nil, fmt.Errorf("failed to connect: %s", connErr)<br> }<br> return pool, nil<br>}</pre><p>This code excerpt is where the AlloyDB Go Connector is configured for pgxpool connection pool. <strong>alloydbconn.WithIAMAuthN()</strong> allows us to use IAM authentication when creating a connection.</p><p>We pass DBNAME, DBUSER and INSTURI as environment variables. “sslmode” is disabled, because the Dialer handles the SSL. You don’t need to manage any certificates and yet the data in transit is encrypted.</p><p>You would notice that we did not pass DB user password (PGPASSWORD) as parameter. Also we didn’t have to pass the IP for AlloyDB Instance as host, instead we used the Instance URI.</p><p>Below call to function connectPostgres() creates a connection pool.</p><pre> db, err := connectPostgres()<br> if err != nil {<br> return err<br> }<br>// just an example<br> data, err = getEmployeesPG(db)<br> if err != nil {<br> log.Printf("func getEmployeesPG: failed to get data: %v", err)<br> return err<br> }</pre><p>Then we can use that connection to query the database in our application.</p><h4>Grant access to IAM user on application database</h4><p>Assuming there is a table called employees in this database “application”. We need to connect to the application databases as BUILTIN User and need to grant appropriate privileges to the IAM DB user.</p><pre><br>grant all privileges on table employees to "${SERVICEACCOUNT}@${PROJECT_ID}.iam";</pre><p>You will need to manage the permissions on the relations as per your application requirements.</p><h4>Deploy and Execute the code on GCE VM</h4><p>This is just an example for demonstration.</p><pre>###Suppose you are in application directory<br>read -p "region : " REGION<br>read -p "projectid : " PROJECT_ID<br>read -p "serviceaccount: " SERVICEACCOUNT<br>export DBNAME=application<br>export DBUSER=${SERVICEACCOUNT}@${PROJECT_ID}.iam<br>export INSTURI=projects/${PROJECT_ID}/locations/${REGION}/clusters/alloydb-cls-$(date +%d%m%Y)/instances/alloydb-ins-primary-$(date +%d%m%Y)<br>go get cloud.google.com/go/alloydbconn<br>go get github.com/jackc/pgx/v5/pgxpool<br>go run ./main.go</pre><p>Application can successfully connect to database to read/write data.</p><h3>For applications deployed on GKE</h3><ul><li>You should have a valid docker container image of your application.</li><li>Workload identity must be enabled at the GKE cluster level.</li><li>Main difference is how the GKE uses Kubernetes service account to authenticate to AlloyDB Database on behalf of Google Service account which is also a Database user in this case. This is done using <a href="https://cloud.google.com/sql/docs/mysql/connect-kubernetes-engine#workload-identity">workload identity</a>.</li><li>We assign iam.workloadIdentityUser role to workload identity service account on your google service account.</li><li>This enables your Kubernetes service account (example alloydb-ksa) to retrieve the authentication token as your google service account (example alloydb-sa) which then can be used to authenticate to AlloyDB as IAM_BASED Database user.</li><li>This Kubernetes service account is then used by the application “deployment” kubernetes resource.</li><li>The environment variables such as DBNAME, DBUSER and INSTURI can be defined in a config map and then that config map can be used by the application “deployment” kubernetes resource.</li></ul><h3>Other Takeaways</h3><ul><li>If you application is written in Java, except the connection pool + Java connector code all steps are same. For connection pool using AlloyDB Java connector, you can use</li></ul><p><a href="https://github.com/GoogleCloudPlatform/alloydb-java-connector/blob/HEAD/alloydb-jdbc-connector/src/test/java/com/google/cloud/alloydb/AlloyDbJdbcConnectorDataSourceFactory.java">alloydb-java-connector/alloydb-jdbc-connector/src/test/java/com/google/cloud/alloydb/AlloyDbJdbcConnectorDataSourceFactory.java at 80864f2b1e3548f3dbfa87f87c95f42f79d363d5 · GoogleCloudPlatform/alloydb-java-connector</a></p><p>and set config.addDataSourceProperty("alloydbEnableIAMAuth", "true");for Automatic IAM Authentication.</p><ul><li>If you desire to use Go connector to connect to your AlloyDB Instance but don’t want to use IAM Authentication, you can use <a href="https://github.com/GoogleCloudPlatform/alloydb-go-connector/blob/HEAD/pgxpool_test.go">https://github.com/GoogleCloudPlatform/alloydb-go-connector/blob/HEAD/pgxpool_test.go</a></li><li>You can configure AlloyDB to accept the connections only through connectors i.e <a href="https://cloud.google.com/alloydb/docs/enforce-connectors">connector enforcement</a>.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ec29c4ee5d2b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/google-cloud/using-alloydb-connector-for-automatic-iam-authentication-service-account-ec29c4ee5d2b">Using AlloyDB Go connector for automatic IAM authentication (service account)</a> was originally published in <a href="https://medium.com/google-cloud">Google Cloud - Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>
Author
Link
Published date
Image url
Feed url
Guid
Hidden blurb
--- !ruby/object:Feedjira::Parser::RSSEntry title: Using AlloyDB Go connector for automatic IAM authentication (service account) published: 2024-04-05 04:49:36.000000000 Z categories: - go - google-cloud-platform - data - postgres - alloydb entry_id: !ruby/object:Feedjira::Parser::GloballyUniqueIdentifier is_perma_link: 'false' guid: https://medium.com/p/ec29c4ee5d2b carlessian_info: news_filer_version: 2 newspaper: Google Cloud - Medium macro_region: Blogs content: '<h3><strong>Introduction</strong></h3><p><a href="https://cloud.google.com/alloydb#documentation">AlloyDB</a> is a fully managed PostgreSQL compatible database service for your most demanding enterprise workloads. AlloyDB combines the best of Google with PostgreSQL, for superior performance, scale, and availability.</p><p>Since AlloyDB is PostgreSQL compatible, you can use <a href="https://github.com/jackc/pgx/">pgxpool</a> and <a href="https://github.com/brettwooldridge/HikariCP/blob/dev/README.md">HikariCP</a> for connection pooling in “Go” and “Java” applications respectively.</p><p>There are two prominent ways to <strong>connect securely to AlloyDB:</strong></p><ul><li>AlloyDB Auth Proxy</li><li>AlloyDB Language connectors</li></ul><h4>AlloyDB Auth Proxy</h4><ul><li><strong>IAM-based connection authorization (AuthZ):</strong> The Auth Proxy uses the credentials and permissions of an IAM principal to authorize connections to AlloyDB instances.</li><li><strong>Secure, encrypted communication:</strong> The Auth Proxy automatically creates, uses, and maintains a TLS 1.3 connection using a 256-bit AES cipher between your client and an AlloyDB instance.</li></ul><h4>AlloyDB Language connectors</h4><p>AlloyDB connectors are the language specific libraries for connecting securely to your AlloyDB instances. Using an AlloyDB connector provides the following additional benefits (besides the ones provided by AlloyDB Auth Proxy) :</p><ul><li><strong>Convenience</strong>: removes the requirement to use and distribute SSL certificates, as well as manage firewalls or source/destination IP addresses. <strong>You also don’t need to manage a separate Auth proxy container or process.</strong></li><li>(optionally) <strong>IAM DB Authentication</strong>: provides support for <a href="https://github.com/GoogleCloudPlatform/alloydb-go-connector?tab=readme-ov-file#automatic-iam-database-authentication">AlloyDB’s automatic IAM DB AuthN</a> feature. That means <strong>you can configure service accounts to connect to database</strong>. For applications deployed on GKE you can use workload identity to authenticate to the backend AlloyDB database.</li></ul><p>AlloyDB Language connectors are available for Go, Java and Python at this time.</p><h3>Purpose</h3><p>If you’re deploying a Go application on GCE/GKE and want to streamline secure connections to your AlloyDB database, the AlloyDB Go connector with IAM authentication is the way to go.</p><p>In this post I will walk you through the process of configuring your application and AlloyDB Instance for using AlloyDB Go connector such that your application can use a service account to connect to AlloyDB database. You don’t need to configure any vault to store the DB user password, no need to store any keyfile for the service account.</p><p>We are considering a hypothetical Go application (<a href="https://github.com/bijeshos/go-postgresql-pgx-example/blob/main/main.go">example</a>) which will be deployed on GCE for this article.</p><h3>Assumptions</h3><ol><li>GCP Project is already created</li><li>VPC network exists for this project and has a subnet defined for GCE/GKE</li><li>AlloyDB, Service Networking, Compute APIs are enabled</li></ol><h3>Steps</h3><h4>Create a service account</h4><p>This is the service account which will be configured as AlloyDB user and will be used by application to connect to database.</p><pre>read -p "project_id: " PROJECT_ID<br>read -p "region: " REGION<br>read -p "serviceaccount: " SERVICEACCOUNT<br>gcloud iam service-accounts create ${SERVICEACCOUNT} --display-name="alloydb service-account" --project ${PROJECT_ID}</pre><h4>Add roles to the service account</h4><p>As per <a href="https://cloud.google.com/alloydb/docs/manage-iam-authn#role,">https://cloud.google.com/alloydb/docs/manage-iam-authn#role,</a> we need to assign roles alloydb.client, alloydb.databaseUser and serviceusage.serviceUsageConsumer to the service account.</p><pre>gcloud projects add-iam-policy-binding ${PROJECT_ID} --member='serviceAccount:${SERVICEACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com' --role='roles/alloydb.client'<br>gcloud projects add-iam-policy-binding ${PROJECT_ID} --member='serviceAccount:${SERVICEACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com' --role='roles/alloydb.databaseUser'<br>gcloud projects add-iam-policy-binding ${PROJECT_ID} --member='serviceAccount:${SERVICEACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com' --role='roles/serviceusage.serviceUsageConsumer'</pre><h4>Create private service access</h4><p>Use Private Services Access to connect to AlloyDB service.</p><p>Private services access requires you to first allocate an internal IPv4 address range and then create a private connection</p><pre>read -p "region : " REGION<br>read -p "projectid : " PROJECT_ID<br>read -p "postgres_password: " PASSWORD<br>read -p "vpc network: " VPC_NETWORK<br><br>gcloud compute addresses create alloydbpsa \<br> --global \<br> --purpose=VPC_PEERING \<br> --prefix-length=16 \<br> --description="Private service access" \<br> --network=$VPC_NETWORK \<br> --project ${PROJECT_ID}</pre><h4>Create VPC private connection to alloydb service</h4><p>Private connection enables private access for AlloyDB Instances</p><pre>gcloud services vpc-peerings connect \<br> --service=servicenetworking.googleapis.com \<br> --ranges=alloydbpsa \<br> --network=$VPC_NETWORK \<br>--project ${PROJECT_ID}</pre><h4>Create AlloyDB Cluster and Primary Instance</h4><p>Below commands will create an AlloyDB Cluster and Instance. Please update the cluster and Instance names as per requirements.</p><pre>read -p "region : " REGION<br>read -p "projectid : " PROJECT_ID<br>read -p "postgres_password: " PASSWORD<br>read -p "vpc network: " VPC_NETWORK<br>gcloud alloydb clusters create alloydb-cls-$(date +%d%m%Y) \<br>--region=${REGION} --password=$PASSWORD --network=${VPC_NETWORK} \<br>--project=${PROJECT_ID}<br><br>gcloud beta alloydb instances create alloydb-ins-primary-$(date +%d%m%Y) \<br>--cluster=alloydb-cls-$(date +%d%m%Y) --region=${REGION} \<br>--instance-type=PRIMARY --cpu-count=2 \<br>--database-flags=alloydb.iam_authentication=on,alloydb.enable_auto_explain=on \<br>--availability-type=ZONAL --project=${PROJECT_ID}</pre><p>Notice that AlloyDB Instance has flag <strong>alloydb.iam_authentication</strong> set to on. This flag enables IAM authentication on an AlloyDB instance. If you already have an AlloyDB Instance, you can use below command to enable this flag.</p><pre>gcloud alloydb instances update $INSTANCE --cluster=$CLUSTER \<br> --region=$REGION --database-flags=alloydb.iam_authentication=on</pre><h4>Create a AlloyDB user with name same as the service account</h4><p>Username must be a same as the service account leaving the suffix “.gserviceaccount.com” and authentication type must be “IAM_BASED”.</p><pre>read -p "serviceaccount: " SERVICEACCOUNT<br>gcloud alloydb users create ${SERVICEACCOUNT}@${PROJECT_ID}.iam \<br>--cluster=alloydb-cls-$(date +%d%m%Y) --type=IAM_BASED \<br>--region=${REGION} --project=${PROJECT_ID}</pre><h4>Create Application schema and grant appropriate roles</h4><p>Connect to AlloyDB database postgres using a BUILTIN user (postgres) to create “application” database and grant appropriate roles to AlloyDB IAM user on “application” database.</p><p>To connect you may use AlloyDB SQL studio or psql.</p><pre>create database application;<br>---replace the ${SERVICEACCOUNT}@${PROJECT_ID}.iam with actual SA<br>grant all privileges on database application to "${SERVICEACCOUNT}@${PROJECT_ID}.iam";</pre><h4>Create GCE Instance</h4><p>Create GCE spot Instance (experimentation purposes only) where our application will be deployed.</p><pre>read -p "GCE subnet:" GCE_SUBNET<br>gcloud compute instances create instance-$(date +%d%m%Y) \<br>--project=${PROJECT_ID} --zone=${REGION}-a --machine-type=e2-medium \<br>--network-interface=network-tier=PREMIUM,stack-type=IPV4_ONLY,subnet=$GCE_SUBNET \<br>--provisioning-model=SPOT --service-account=${SERVICEACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com \<br>--scopes=https://www.googleapis.com/auth/cloud-platform \<br>--create-disk=auto-delete=yes,boot=yes,device-name=instance-$(date +%d%m%Y)-230433,image=projects/debian-cloud/global/images/debian-12-bookworm-v20240213,mode=rw,size=10,type=projects/${PROJECT_ID}/zones/${REGION}-a/diskTypes/pd-balanced \<br>--no-shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring \<br>--labels=goog-ec-src=vm_add-gcloud --reservation-affinity=any \<br>--preemptible --metadata=startup-script='#! /bin/bash<br> apt update -y<br> apt -y install golang unzip git'</pre><p>Notice that we bind the service account (DB User Service Account) that we created earlier to the GCE VM.</p><p>Now any process running on GCE VM can use that service account to authenticate to allowed APIs using assigned roles.</p><h4>Connecting to postgres using pgx pool (no connector)</h4><p>To make a connection to your database you would typically be using a function such as below. This uses <a href="https://pkg.go.dev/github.com/jackc/pgx/v5/pgxpool#pkg-overview">pgxpool package</a> to create a connection pool.</p><pre>func connectPostgres() (*pgxpool.Pool, error) {<br> ctx := context.Background()<br> var (<br> dsn string<br> dbname = os.Getenv("DBNAME")<br> user = os.Getenv("DBUSER")<br> host = os.Getenv("PGHOSTNAME")<br> password = os.Getenv("PGPASSWORD")<br> err error<br> )<br><br> dsn = fmt.Sprintf(<br> //user=jack password=secret host=pg.example.com port=5432 dbname=mydb sslmode=verify-ca pool_max_conns=10<br> // connection instead.<br> "user=%s password=%s dbname=%s sslmode=disable host=%s",<br> user, password, dbname, host,<br> )<br> config, err := pgxpool.ParseConfig(dsn)<br> if err != nil {<br> return nil, fmt.Errorf("failed to parse pgx config: %v", err)<br> }<br> // Establish the connection.<br> pool, connErr := pgxpool.NewWithConfig(ctx, config)<br> if connErr != nil {<br> return nil, fmt.Errorf("failed to connect: %s", connErr)<br> }<br> return pool, nil<br><br>}</pre><p>This requires you to define environment variables DBNAME, DBUSER, PGHOSTNAME and PGPASSWORD.</p><p>If you want to encrypt the data in transit, you have to configure sslmode and configure TLS certificates to encrypt the data in transit. You will need to manage the certificates on the application host.</p><h4>Connecting to postgres using pgx pool and Go Connector</h4><p>Update the definition of connectPostgres() in your application to the below.</p><pre>func connectPostgres() (*pgxpool.Pool, error) {<br> ctx := context.Background()<br>// export DBNAME=application<br>// export DBUSER=${SERVICEACCOUNT}@${PROJECT_ID}.iam<br>// export INSTURI=projects/${PROJECT_ID}/locations/${REGION}/clusters/alloydb-cls--$(date +%d%m%Y)/instances/alloydb-ins-primary--$(date +%d%m%Y)<br> var (<br> dsn string<br> dbname = os.Getenv("DBNAME")<br> user = os.Getenv("DBUSER")<br> instURI = os.Getenv("INSTURI")<br> )<br>// A Dialer can be configured to connect to an AlloyDB instance <br>// using automatic IAM database authentication with the WithIAMAuthN Option.<br> d, err := alloydbconn.NewDialer(ctx, alloydbconn.WithIAMAuthN())<br>if err != nil {<br> return nil, fmt.Errorf("failed to init Dialer: %v", err)<br> }<br> dsn = fmt.Sprintf(<br> // sslmode is disabled, because the Dialer will handle the SSL<br> // connection instead.<br> "user=%s dbname=%s sslmode=disable",<br> user, dbname,<br> )<br> config, err := pgxpool.ParseConfig(dsn)<br> if err != nil {<br> return nil, fmt.Errorf("failed to parse pgx config: %v", err)<br> }<br> // Tell pgx to use alloydbconn.Dialer to connect to the instance.<br> config.ConnConfig.DialFunc = func(ctx context.Context, _ string, _ string) (net.Conn, error) {<br> return d.Dial(ctx, instURI)<br> }<br> // Establish the connection.<br> pool, connErr := pgxpool.NewWithConfig(ctx, config)<br> if connErr != nil {<br> return nil, fmt.Errorf("failed to connect: %s", connErr)<br> }<br> return pool, nil<br>}</pre><p>This code excerpt is where the AlloyDB Go Connector is configured for pgxpool connection pool. <strong>alloydbconn.WithIAMAuthN()</strong> allows us to use IAM authentication when creating a connection.</p><p>We pass DBNAME, DBUSER and INSTURI as environment variables. “sslmode” is disabled, because the Dialer handles the SSL. You don’t need to manage any certificates and yet the data in transit is encrypted.</p><p>You would notice that we did not pass DB user password (PGPASSWORD) as parameter. Also we didn’t have to pass the IP for AlloyDB Instance as host, instead we used the Instance URI.</p><p>Below call to function connectPostgres() creates a connection pool.</p><pre> db, err := connectPostgres()<br> if err != nil {<br> return err<br> }<br>// just an example<br> data, err = getEmployeesPG(db)<br> if err != nil {<br> log.Printf("func getEmployeesPG: failed to get data: %v", err)<br> return err<br> }</pre><p>Then we can use that connection to query the database in our application.</p><h4>Grant access to IAM user on application database</h4><p>Assuming there is a table called employees in this database “application”. We need to connect to the application databases as BUILTIN User and need to grant appropriate privileges to the IAM DB user.</p><pre><br>grant all privileges on table employees to "${SERVICEACCOUNT}@${PROJECT_ID}.iam";</pre><p>You will need to manage the permissions on the relations as per your application requirements.</p><h4>Deploy and Execute the code on GCE VM</h4><p>This is just an example for demonstration.</p><pre>###Suppose you are in application directory<br>read -p "region : " REGION<br>read -p "projectid : " PROJECT_ID<br>read -p "serviceaccount: " SERVICEACCOUNT<br>export DBNAME=application<br>export DBUSER=${SERVICEACCOUNT}@${PROJECT_ID}.iam<br>export INSTURI=projects/${PROJECT_ID}/locations/${REGION}/clusters/alloydb-cls-$(date +%d%m%Y)/instances/alloydb-ins-primary-$(date +%d%m%Y)<br>go get cloud.google.com/go/alloydbconn<br>go get github.com/jackc/pgx/v5/pgxpool<br>go run ./main.go</pre><p>Application can successfully connect to database to read/write data.</p><h3>For applications deployed on GKE</h3><ul><li>You should have a valid docker container image of your application.</li><li>Workload identity must be enabled at the GKE cluster level.</li><li>Main difference is how the GKE uses Kubernetes service account to authenticate to AlloyDB Database on behalf of Google Service account which is also a Database user in this case. This is done using <a href="https://cloud.google.com/sql/docs/mysql/connect-kubernetes-engine#workload-identity">workload identity</a>.</li><li>We assign iam.workloadIdentityUser role to workload identity service account on your google service account.</li><li>This enables your Kubernetes service account (example alloydb-ksa) to retrieve the authentication token as your google service account (example alloydb-sa) which then can be used to authenticate to AlloyDB as IAM_BASED Database user.</li><li>This Kubernetes service account is then used by the application “deployment” kubernetes resource.</li><li>The environment variables such as DBNAME, DBUSER and INSTURI can be defined in a config map and then that config map can be used by the application “deployment” kubernetes resource.</li></ul><h3>Other Takeaways</h3><ul><li>If you application is written in Java, except the connection pool + Java connector code all steps are same. For connection pool using AlloyDB Java connector, you can use</li></ul><p><a href="https://github.com/GoogleCloudPlatform/alloydb-java-connector/blob/HEAD/alloydb-jdbc-connector/src/test/java/com/google/cloud/alloydb/AlloyDbJdbcConnectorDataSourceFactory.java">alloydb-java-connector/alloydb-jdbc-connector/src/test/java/com/google/cloud/alloydb/AlloyDbJdbcConnectorDataSourceFactory.java at 80864f2b1e3548f3dbfa87f87c95f42f79d363d5 · GoogleCloudPlatform/alloydb-java-connector</a></p><p>and set config.addDataSourceProperty("alloydbEnableIAMAuth", "true");for Automatic IAM Authentication.</p><ul><li>If you desire to use Go connector to connect to your AlloyDB Instance but don’t want to use IAM Authentication, you can use <a href="https://github.com/GoogleCloudPlatform/alloydb-go-connector/blob/HEAD/pgxpool_test.go">https://github.com/GoogleCloudPlatform/alloydb-go-connector/blob/HEAD/pgxpool_test.go</a></li><li>You can configure AlloyDB to accept the connections only through connectors i.e <a href="https://cloud.google.com/alloydb/docs/enforce-connectors">connector enforcement</a>.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ec29c4ee5d2b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/google-cloud/using-alloydb-connector-for-automatic-iam-authentication-service-account-ec29c4ee5d2b">Using AlloyDB Go connector for automatic IAM authentication (service account)</a> was originally published in <a href="https://medium.com/google-cloud">Google Cloud - Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>' rss_fields: - title - published - categories - entry_id - content - url - author url: https://medium.com/google-cloud/using-alloydb-connector-for-automatic-iam-authentication-service-account-ec29c4ee5d2b?source=rss----e52cf94d98af---4 author: Harinderjit Singh
Language
Active
Ricc internal notes
Imported via /usr/local/google/home/ricc/git/gemini-news-crawler/webapp/db/seeds.d/import-feedjira.rb on 2024-04-05 09:23:06 +0200. Content is EMPTY here. Entried: title,published,categories,entry_id,content,url,author. TODO add Newspaper: filename = /usr/local/google/home/ricc/git/gemini-news-crawler/webapp/db/seeds.d/../../../crawler/out/feedjira/Blogs/Google Cloud - Medium/2024-04-05-Using_AlloyDB_Go_connector_for_automatic_IAM_authentication_(ser-v2.yaml
Ricc source
Show this article
Back to articles