[GCP] More secure with Service Account Impersonation

Burasakorn Sabyeying
Mils’ Blog
Published in
3 min readJun 3, 2021

สวัสดีค่ะ บทความนี้เราจะเล่าถึงการใช้ Service Accountใน Google Cloud Platform ในแบบที่ secure มากขึ้นใน scenario ที่จะกล่าวค่ะ

ในการที่เราจะดึงข้อมูลต่างๆใน Google Cloud Service นั้น Concept หนึ่งที่สำคัญมากๆเลยก็คือ Service Account ค่ะ

สมมติว่าโจทย์เราคือ

อยากดึงข้อมูลใน BigQuery มาดูโดยจะดึงผ่าน programmatic แล้วเนี้ย

สิ่งเราจะต้องทำ คือไปสร้าง Service Account นี้เพื่อบอกว่า Service Account ตัวนี้นะ จะเป็นคนที่มีสิทธิ์ (role) เข้าถึง resouce ข้างใน BigQuery นะ

ซึ่งแค่นี้ไม่พอนะ ตอนเราเขียนโค้ดเนี้ย สิ่งที่เราต้องใช้คือ credential file ค่ะ ซึ่งจะมาอยู่ในรูปแบบของ JSON หรือ P12 file เพื่อยืนยันตัวตนของเรา
และ credential file ตัวนี้ก็กด download มาจาก service account ที่เราสร้างเลยค่ะ

def get_service(api_name, api_version, scopes, key_file_location):
"""Get a service that communicates to a Google API.
"""
credentials = ServiceAccountCredentials.from_json_keyfile_name(
key_file_location, scopes=scopes)
# Build the service object.
service = build(api_name, api_version, credentials=credentials)

จะเห็นได้ว่า key_file_location จะเป็นการระบุว่าไฟล์อยู่ที่ไหน = มีไฟล์

ฟังแบบไม่คิดอะไรแล้วก็ดูดีเนอะ แต่ความจริงแล้ว ปัญหามันอยู่ตรงนี้แหล่ะค่ะ

ถ้าโจทย์ถัดมาของเราคือ

สมมติว่าเราอยากให้ลูกค้า ซึ่งเป็นคนนอก project อยากเข้าถึง BigQuery ได้

เขาดึงข้อมูลได้เหมือนกัน (แหม่ ก็เจ้าของข้อมูลอ่ะเนอะ)

ดังนั้น สิ่งที่เราทำคือต้องส่ง key file ให้เขาใช่ไหมคะ

ปัญหาคือ Key file ที่เราได้มาเนี้ย มันมี private key ข้างใน ซึ่งแปลว่า ถ้าใครได้ key file นี้ไป ถ้า key นี้หลุดไปจากลูกค้าอีกที คนไม่หวังดีก็มีโอกาสเอาไปใช้ได้ด้วย

งั้นทำยังไงดี?

เอาจริงๆในเรื่อง Security เอง Google เขาได้บอกไว้แล้วว่า สิ่งที่คุณต้องทำคือ จำกัดสิทธิ์ให้เป็น role เท่าที่คุณต้องใช้เท่านั้น และเขาแนะนำให้ใช้ Service Account Impersonation

การ Impersonate คืออะไร ?

Impersonate = allow members and resources to /impersonate/, or act as, an Identity and Access Management (IAM) service account

คือให้คนที่เรา allowed สามารถ impersonate/pretend to be เป็น service account นั้นโดยที่จำกัดสิทธิ์ตามที่กำหนดไว้

End user พยายาม impersonate เป็น SA นั้นที่มีสิทธิ์เข้าถึง BQ

ซึ่ง ต่อจากนี้ เราจะสอนแบบ step by step เลย

ไปที่ Google Cloud Platform
กดจาก tab IAM & Admin > Service Accounts แล้วกด create service account

ตั้งชื่อว่า bigquery-editor เพื่อให้ยึดตามหน้าที่ของนาง

set role เป็น BigQuery Editor

จะได้

จะเห็นว่า No key เพราะเราจะไม่สร้าง credential file ตรงนี้เด็ดขาด

ต่อไปเราจะให้สิทธิ์กับคนที่จะเข้ามา

โดยเรากดเข้า service account ที่สร้างมาตะกี้ กดตรง tab permission > กด grant access

เราจะให้เมลล์คน mils.meso@gmail.com เข้ามาเป็นสิทธิ์ Service Account Token Creater

สรุปตอนนี้

  • เราให้ mils.meso@gmail เป็น Service Account Token Creator
    (มีสิทธิ์สร้างได้แค่พวก access token ต่างๆ)
  • เราสร้าง service account ตัว bigquery-editor@single-outrider-315704.iam.gserviceaccount.com เป็น bigquery editor

ซึ่งเมลล์มนุษย์จะ impersonate เป็น Service Account ตัวที่มีสิทธิ์เข้าถึง BigQuery ได้

คราวนี้เทสซิ

เราจะใช้คือ gcloud SDK ค่ะ
ทดสอบด้วยการรัน command ด้านล่าง แล้วจะ redirect มาหน้า browser ที่เป็น account ที่เราอยากให้มีสิทธิ์เข้าถึง GCP ค่ะ

gcloud auth application-default login
redirect มาหน้า login

คราวนี้ลอง list ว่า project ตอนนี้เข้าถึงอะไรได้บ้าง

gcloud projects list

จะเห็นได้ว่าเราสามารถเข้าถึง project นี้ได้แล้ว

ต่อไป เราจะลองดูว่าสามารถเข้าใช้ BigQuery ได้จริงๆรึเปล่า

ไหนลอง query ดูจำนวน column ใน BigQuery ซิ
(ต้องลง package google-cloud-bigquery ด้วยนะ)

import google.auth
import google.auth.impersonated_credentials
from google.cloud import bigquerytarget_scopes = [
https://www.googleapis.com/auth/bigquery",
https://www.googleapis.com/auth/bigquery.readonly"
]
credential, project_id = google.auth.default()
print(f”Obtained default credentials for the project {project_id}”)
sa_cred = google.auth.impersonated_credentials.Credentials(
source_credentials=credential,
target_principal=”bigquery-editor@single-outrider-315704.iam.gserviceaccount.com”,
target_scopes=target_scopes,
lifetime=500 #upto 3600 secs
)
client = bigquery.Client(credentials=sa_cred)
table_id = ‘single-outrider-315704.medium_share.students_performance’
table = client.get_table(table_id) # Make an API request.
print(“Table {} contains {} columns”.format(table_id, len(table.schema)))

อย่าลืม

pip install --upgrade google-cloud-bigquery

จะได้ผลลัพท์คือ

เรา print ออกมาว่า table ของเรามี 8 columns

โดยที่ credential ที่ถูก generate ใน coding เราจะมีอายุได้มากสุด 3600 second (1 hr) เท่านั้น

โดยที่เราไม่ต้องถือ key file ไว้กับตัว

ขอบคุณที่อ่านถึงตรงนี้ค่ะ

--

--

Burasakorn Sabyeying
Mils’ Blog

Data engineer at CJ Express. Women Techmakers Ambassador. GDG Cloud Bangkok team. Moved to Mesodiar.com