AWS Web Identity Federation In Action! (Flask + Elastic Beanstalk Env.)

Mart — Tanathip Viriya
5 min readJul 6, 2020

--

Web Identity Federation — Recap

  • เวลาเขียน application ที่ต้องการจะ access เข้าถึง AWS resources ต่างๆมันต้องการ access key ซึ่งไม่แนะนําให้ไปใส่ไว้ใน application โดยเด็ดขาด สิ่งที่เราควรทําคือใช้ requests temporary credentials เพื่อเข้าถึง AWS resource โดยผ่าน web identity federation
  • web identity federation แบ่งเป็น identity consumer (App เรานั้นแหละ), broker (ตัวกลาง ที่คอยจัดการระหว่าง consumer และ provider ซึ่งของ AWS ก็คือ Cognito) และ provider (Login with Facebook, Google, Amazon เป็นต้น)
  • AWS Cognito (Identity Broker) — recommend สําหรับ mobile application
  • แต่ถ้าเราไม่ได้ทํา Mobile app แต่เป็น Web app เราจะต้องเขียนโค้ดขึ้นมาจัดการทํา authentication กับ IdPs เพื่อเอา credential เอง แล้วก็ไปเรียก AssumeRoleWithWebIdentity เพื่อเข้าถึง AWS Resources โดย sequence diagram อยู่ด้านล่างนี้
sequence diagram of Web IdP

ตัวอย่างวันนี้

วันนี้ที่จะทําก็คือ เขียน Web Application ที่ทําการ list bucket S3 ทั้งหมดของเราออกมา โดย Flow การทํางานจะมีรูปร่างแบบ diagram ข้างบนเลย และจะทําการ deploy บน Elastic beanstalk เนื่องจากขี้เกรี้ยจนั่งตั้งค่า EC2 นั้นเอง (ใช้ CloudFormation เขียน Infrastructure และ ใช้ Flask กับ Boostrap เป็น Web Application)

ก่อนอื่นมา Recap ในหัวข้อที่เกี่ยวข้องกันก่อน

Elastic Beanstalk Config จัดการยังไง

อยากรู้ EB (Elastic Beanstalk) คร่าวๆๆแบบ recap สามารถอ่านได้ตรงนี้เลย

เพราะเดี๋ยวเราจะพูดแต่เรื่อง configuration ของ EB อย่างเดียวเท่านั้นละ

เริ่มง่ายๆเลยคือ EB มันเป็น Ready-to-use environment เพราะฉะนั้นๆๆหลักของการใช้งาน EB เลยก็คือเรื่องของการ config มันเนี้ยแหละ โดยการ config ทั้งหมดของ EB จะต้องสร้าง Folder ชื่อ

.ebextensions

แล้วอะไรก็ตามที่เป็น

*.config

จะถูกนําไปใช้ตอนสร้าง Environment นั้นเอง โดยไฟล์พวกนี้มันจะถูกทํางานตาม alphabetical order แปลว่าเราสามารถตั้งชื่อแบบ

  • 01run.config
  • 02do.config

แล้วก็ไล่ต่อไปเรื่อยๆได้ เพื่อให้มันเรียงลําดับในการทํางานได้นั้นเอง โดย syntax ของ Configuration จะเป็นตามรูปด้านล่าง

https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environment-configuration-methods-before.html

การทํางานทั้งหมดจะขึ้นกับ Namespace ที่เราใช้งาน เช่น สมมุติเราต้องการที่จะทําการ health check หลัง deploy application เสร็จ เราจะสร้าง option ตัวนึงและ namespace ชื่อ aws:elasticbeanstalk:application และใส่ค่า value เป็ร endpoint สําหรับให้ EB ส่ง HTTP request เข้าไป

https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environment-configuration-methods-before.html

ดู namespace ลิสทั้งหมดได้ที่ลิ้งค์ด้านล่างนี้เลย

อีกวิธีนึงคือนอกจากเราจะใช้ config ใน .ebextensions แต่เราสามารถใช้สิ่งที่เรียกว่า saved configurations โดยเป็นการเอา configuration ไปใส่ใน Amazon Simple Storage Service (Amazon S3) ซึ่ง EB environment อื่นๆสามารถนําไปใช้ได้ในระหว่างสร้าง environment

ซึ่งไฟล์ saved configurations พวกนี้จะถูกเก็บไว้ในที่เดียวกับ AWS EB CLI folder ซึ่งก็คือ .elasticbeanstalk

https://docs.amazonaws.cn/en_us/elasticbeanstalk/latest/dg/environment-configuration-methods-during.html

นอกจากนั้นเรายังสามารถสร้าง Customize Option ของเราเองได้ด้วย

แต่จุดสําคัญอีกอย่างของการ configuration Elastic Beanstalk ก็คือเรื่องของ Elastic Beanstalk platforms (หรือ SolutionStack ที่เราใช้ใน CloudFormation เวลาสร้าง) ว่าเราใช้ตัวไหน เช่น

  • Amazon Linux 2
  • และก่อนหน้า Amazon Linux 2 ทั้งหมด

เพราะว่า configuration ใน 2 versions ของ Amazon Linux ไม่เหมือนกัน เช่น ถ้าเราทํา Node Platform แล้วใช้ configuration เก่าๆอย่าง

https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_nodejs.container.html

จะทําให้เกิด Error ทีเรียกว่า

Environment failed to launch as it entered Terminated state

ซึ่งเกิดจาก EC2 role ได้ หรือเกิดจาก Configuration ผิดก็เป็นได้

Elastic Beanstalk Development Platform

เนื่องจากอย่างที่เรารู้คือ EB คือการเตรียม environment แบบง่ายๆเพื่อให้เราไม่ต้องเสียเวลาจัดการ server เอง

ทีนี้เราต้องดู Application ของเราใช้ภาษาอะไรในการสร้าง เพราะฉะนั้นเวลาเราสร้าง environment เราก็ต้องสร้าง Option ที่เลือก platform ของภาษานั้นๆ เช่น Python

https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-specific.html#command-options-python

กับพวก options ต่างๆที่เราต้องใส่เข้าไปนั้นเอง เช่นของ Python เราต้องใส่ WSGI application เพื่อจะให้เรียก file ไหนนั้นเอง

Python Web Application — Recap

  • เวลาเราทํา Web Application ด้วย Python เราจะมีสองตัวเลือกคือ Django หรือ Flask โดยปกติง่ายๆๆเร็วๆ เราจะเลือก Flask
  • ซึ่ง Flask ก็ใช้ Template Engine ชื่อ Jinja ในการทํา render หน้า UI ออกมา ทีนี้เรา
    https://flask.palletsprojects.com/en/1.1.x/tutorial/templates/

Web Identity Federation Tutorial

Web Federation Project — Google Sign in

Repository: https://github.com/howtoautomateinth/awesome-aws-workshop/tree/master/WebIdentity

ภาพรวมโปรเจค

สิ่งที่โปรเจคนี้ทําเลยคือทํา hybrid sign-in กับ ทาง Google เพื่อไป List S3 buckets ทั้งหมดที่มีอยู่ของเราออกมาโชว์

โดยหลักๆใช้

  • jquery — จัดการพวก Interaction
  • bootstrap — ทําหน้า UI
  • flask — เป็น Web Server Application
  • Elastic Beanstalk — เป็น Infrastructure ของโปรเจค

จุดสําคัญของ Project ก็คือ

  1. สร้าง Elastic Beanstalk environment สําหรับการทํางานของด้วย CloudFormation Template เพื่อใช้ในการจัดการเป็น Infrastructure ของโปรเจค
  2. เราจะ redirect request ไป Identity Provider อย่าง Google เพื่อ Authentication ได้ valid token กลับมา
  3. แล้วค่อยเอา Token มาแลกกับ AWS temporary token ของ services AWS STS แล้วเอาไปใช้ทําอะไรก็ได้ตาม policy ที่เราใช้ ซึ่งในที่นี้ก็คือ S3 นั้นเอง

ให้ดู repository ข้างบนเป็นตัวอย่างในการใช้งาน แต่ว่าถ้าจะนําไปใช้จริงๆอาจจะต้องไป

  1. setup project ใน gcloud เพื่อเอา API key และ domain ของ firebase มาเติมใน file app.js
  2. รวมถึง enable identity platform ใน google cloud เพื่อให้สามารถ Login ได้
  3. สร้าง Role เพื่อกําหนด policy พร้อม trust relation กับทาง google เพื่อใช้ในการทํา AssumeRoleWithWebIdentity ใน AWS เพื่อให้เราไปเอามาใช้ได้

ข้อควรระวังของการ AssumeRoleWithWebIdentity

  • Document ของ AWS เรื่อง Trust Policy ชวนสับสนมากๆๆ มันจะมีจุดนึงพูดเรื่องการสร้าง Role ของ Google Oauth2 ว่าให้ใส่ app id ซึ่งจริงๆแล้วใน Google Cloud คือ ClientId นั้นเอง ทีนี้เวลาเราสร้าง Trust policy สิ่งที่เราต้องทําก็คือใส่ Client Id ทั้งหมดยาวๆๆลงไปตามตัวอย่างด้านล่าง
Sample of trust policy
Credentials section in APIs & Services
  • ณ ปัจจุบันวันที่ 6/7/2020 — Google ยกเลิก Identity API ไปละ ให้ใช้ Identity Platform แทนเพื่อเอา Token ID ใช้ในการ Validation ซึ่งใช้เจ้า Firebase Authentication เป็นหลัก ซึ่งสามารถทําได้ง่ายๆเลย โดยการทําตามตัวอย่างด้านล่าง (จุดสําคัญอีกอย่างคือเราต้องใช้ idToken นะ ไม่ใช้ access_token เพราะว่าหลัง authentication มันจะ return กลับมา 2 ตัว)
https://github.com/howtoautomateinth/awesome-aws-workshop/blob/master/WebIdentity/static/js/app.js

Elastic Beanstalk CloudFormation

ทีนี้เนื่องจากเราไม่อยากทําแค่ใน Local เราอยากให้ application เราไป Online บน AWS Environment ด้วย

ดังนั้นในส่วนของ Environment บน AWS เราจะใช้ CloudFormation เป็นตัวสร้างให้

Cfn File: https://hta-cloudformation-bucket.s3.amazonaws.com/Elasticbeanstalk/Flask/template.yml

สิ่งที่ต้องทําก็คือไปเปลี่ยน Location ของ SourceBundle เป็นของตัวเอง แค่นั้นก็สามารถ deploy ขึ้น EB ของตัวเองได้เลย

Troubleshooting CloudFormation Elastic Beanstalk

  • SolutionStackName ใน Template ที่เราต้องเลือก มีผลต่อการ configuration ต่างๆๆใน Template ด้วย เช่น ตัวอย่างเราใช้ 64bit Amazon Linux 2 v3.0.3 running Python 3.7 เวลา setup WSGIPath เราจะไม่ต้องใส่ extension .py นั้นเอง
Sample SolutionStackName effect
  • EC2Keypair ใน Configuration Template เป็นเรื่องจําเป็นมาก!!! สําหรับ Cfn คือถ้าไม่ใส่ จะเกิดเรื่องของ Target.ResponseCodeMismatch ทันท ีคาดว่าเพราะว่า security ที่จะเข้าไป access มันทําไม่ได้ ทําให้เลยพังนั้นเอง (แล้ว Error ก็ไม่ได้สื่อเลยยยยยย ทําเอา งง ได้เลย)
  • เวลาเรา Deploy ขึ้น EB แล้วสิ่งที่เราต้องทําก็คือ นํา domain เราไปใส่ใน firebase ด้วยเพื่อให้มัน redirect กลับไปที่ Authentication domain นั้นๆได้นั้นเอง (login เข้าอันนี้ https://firebase.google.com/ แล้วไปตรง authentication แล้วเพิ่ม Authorized domainsได้เลย)

--

--