EC2 IAM Role/IAM Instance Profile as Code

tl;dr: Konfigurasi EC2 IAM Role/IAM Instance Profile menggunakan IaC tool (Terraform).

Amazon EC2 sebagai service atau layanan compute atau virtual machine yang disediakan oleh Amazon Web Services (AWS) mungkin merupakan salah satu service yang paling sering kita jumpai atau gunakan dalam keseharian.

Penggunaannya pun bermacam-macam, bisa dijadikan sebagai backend untuk container service seperti ECS, menjadi instance database, menjadi server aplikasi, berfungsi sebagai bastion host/jumphost dan lain sebagainya.

Pada operasional sehari-hari juga kita sering jumpai dimana kita perlu mengakses layanan atau service lain dari AWS melalui EC2. Contohnya kita perlu meng-upload file dari server EC2 ke S3 melalui AWS CLI dan lainnya. Agar proses seperti ini dapat berjalan, diperlukan credentials terkait seperti AWS Access Key dan AWS Secret Key. Dan credentials tersebut disimpan di dalam EC2/server.

Dari hal di atas kita jumpai potensi masalah lain. Karena AWS Access Key dan AWS Secret Key disimpan atau ditanam ke dalam EC2 instance, dapat membuka celah bagi orang yang tidak berkepentingan untuk membaca file credential tersebut. Dan dapat mengakibatkan AWS Access Key dan AWS Secret Key dapat digunakan oleh orang yang tidak berkepentingan untuk menjalankan resource/service di akun AWS kita. Selain itu juga dapat muncul potensi masalah lain, jika EC2 yang memerlukan akses ke layanan lain jumlahnya banyak, dan kita perlu mengkonfigurasi atau memasukkan AWS Access Key dan AWS Secret Key satu per satu ke setiap instance, tentulah hal ini menjadi hal yang melelahkan.

Untuk mengantisipasi hal ini, AWS sudah menyediakan alternatif lain jika EC2 kita memerlukan akses ke layanan atau service lain. Kita dapat memberikan IAM Role atau yang sering juga disebut IAM Instance Profile ke dalam EC2 instance kita. Dengan menggunakan EC2 IAM Role, kita tidak perlu memasukkan credentials yang sifatnya sensitif ke dalam EC2 instance kita sehingga dapat meminimalisir celah keamanan/security. Yang perlu kita lakukan adalah membuat IAM Role dimana IAM role ini akan di-associate ke EC2 service dan juga akan di associate ke IAM policy yang dapat disesuaikan sejauh mana EC2 dapat mengakses layanan/service AWS lainnya.

Konfigurasi ini sebetulnya dapat dilakukan baik via Web Console atau melalui programmatic access seperti Infrastructure as Code. Pada artikel ini, saya akan coba membahas konfigurasi dari sudut pandang Infrastructure as Code (IaC). Jadi seluruh konfigurasi dilakukan via IaC.

Skenario yang saya gunakan pada artikel ini adalah saya akan mengkonfigurasi EC2 IAM Role/IAM Instance Profile yang akan di-associate ke EC2 service. Kemudian IAM Role akan di-associate ke IAM Policy, dimana pada artikel ini IAM Policy yang digunakan adalah AWS Managed Policy. Setelah EC2 IAM Role dideklarasikan, selanjutnya IAM Role tersebut akan di associate ke EC2 instance yang berjalan menggunakan sistem operasi Ubuntu 20.04. Konfigurasi dilakukan menggunakan IaC tool Terraform dan metode yang digunakan adalah Terraform CLI.

Jika anda tertarik untuk mempelajari dasar-dasar Terraform CLI, silahkan kunjungi blog post saya yang membahas hal tersebut di link berikut: Provision Amazon EC2 Menggunakan Terraform CLI.

Persiapan

Sebelum memulai konfigurasi, ada beberapa komponen yang harus disiapkan. Berikut diantaranya:

  • Terraform CLI yang sudah terinstall. Untuk langkah instalasi silahkan lihat di URL berikut: Install Terraform.

  • AWS Access Key, Secret Access Key, profile (default ataupun named profile) yang sudah dikonfigurasi via AWS CLI. Silahkan lihat detailnya di URL berikut: Configuring the AWS CLI. AWS Access Key dan Secret Access Key digunakan untuk credential yang digunakan oleh Terraform di local notebook agar dapat mengakses API di AWS dan dapat menjalankan service via code.

Konfigurasi

Pada artikel ini, EC2 IAM Role akan saya deklarikasan sebagai module (Terraform local module), kemudian module akan dipanggil di main code EC2. Tujuannya adalah agar lebih fleksibel, berbagai macam IAM Role dengan policy yang berbeda dapat di-associate ke berbagai macam EC2 juga sesuai dengan kebutuhannya.

Berikut struktur directory yang digunakan:

ec2/
├─ main.tf
├─ outputs.tf
├─ user-data.sh
├─ variables.tf
modules/
├─ iam/
      ├─ iam_roles.tf
      ├─ outputs.tf
      ├─ variables.tf

Berikut langkah-langkah konfigurasinya:

  1. Konfigurasi kita mulai dengan membuat local terraform module untuk IAM. File pertama yang kita bahas adalah /modules/iam/iam_roles.tf.

    Image

    Di file ini kita mulai dengan membuat atau generate data IAM Policy agar dapat memiliki akses sts:AssumeRole ke service ec2.

     # Generate assume role policy
     data "aws_iam_policy_document" "ec2-assume-role" {
       statement {
         actions = ["sts:AssumeRole"]
    
         principals {
           type        = "Service"
           identifiers = ["ec2.amazonaws.com"]
         }
       }
     }
    

    Setelah itu membuat iam instance profile dimana role nya mengacu ke iam role dengan nama yang sama yaitu "ludes-ec2-admin-role". Pada resource iam role "ludes-ec2-admin-role" saya deklarasikan nama, path dan assume role nya mengacu ke document data iam policy di atas yang kemudian di convert ke format json. Dan terakhir untuk iam policy yang digunakan atau di attach ke role adalah managed policy aws. Parameter-parameter di atas kesemuanya mengacu ke variable yang sudah di deklarasikan di dalam file /modules/iam/variabels.tf.

     # Configure IAM instance profile
     resource "aws_iam_instance_profile" "ludes-ec2-admin-role" {
       name = var.iam-role-name
       role = aws_iam_role.ludes-ec2-admin-role.name
     }
     # Configure IAM role
     resource "aws_iam_role" "ludes-ec2-admin-role" {
       name                  = var.iam-role-name
       path                  = var.iam-role-path
       assume_role_policy    = data.aws_iam_policy_document.ec2-assume-role.json
       managed_policy_arns   = var.iam-role-policy-attachment
     }
    
  2. File berikutnya yang akan kita bahas adalah /modules/iam/variables.tf.

    Image

    Pada file ini saya deklarasikan variable variable yang digunakan di /modules/iam/iam_roles.tf.

    variable iam-role-name digunakan untuk memberikan nama IAM role, variable iam-role-path digunakan untuk mendeklarasikan path IAM role. Kemudian variable iam-role-policy-attachment digunakan untuk mendeklarasikan AWS Managed Policy yang di-associate. Pada artikel ini saya menggunakan AmazonEC2FullAccess dan AmazonS3FullAccess karena untuk keperluan demo di artikel ini saja. Pada production environment sebaiknya gunakan least privilege policy, jadi hanya mengizinkan akses terbatas/paling minimal sesuai yang dibutuhkan.

     # Define role name
     variable "iam-role-name" {
       type        = string
       description = "IAM role name"
       default     = "ludes-ec2-admin-role"
     }
    
     # Define role path
     variable "iam-role-path" {
       type        = string
       description = "IAM role path"
       default     = "/"
     }
    
     # Define Policy. Policy consist list of AWS managed polices
     variable "iam-role-policy-attachment" {
       type        = list(string)
       description = "List of IAM policies"
       default     = [
                       "arn:aws:iam::aws:policy/AmazonEC2FullAccess",
                       "arn:aws:iam::aws:policy/AmazonS3FullAccess" 
                     ] 
     }
    
  3. Selanjutnya kita akan bahas file /modules/iam/outputs.tf.

    Image

    Pada file ini, saya mendeklarasikan 1 ouput dengan nama iam-instance-profile-name. Output ini akan menampilkan nama iam instance profile yang sudah kita buat dan ini yang akan digunakan sebagai acuan oleh ec2 main.tf.

     # Generate output of IAM role name
     output "iam-instance-profile-name" {
       value       = aws_iam_instance_profile.ludes-ec2-admin-role.name
       description = "IAM role name"
     }
    
  4. File selanjutnya yang akan kita bahas adalah /ec2/main.tf. Folder ec2 disini akan bertindak sebagai root module dan akan menggunakan referensi dari folder /modules/iam sebagai child module.

    Image

    Hal pertama yang dilakukan adalah konfigurasi terraform providers dan region yang digunakan. Terkait credential yang digunakan, pada artikel ini saya menggunakan metode shared credential file yang telah dideklarasikan sebagai variable di variables.tf.

     # Setup terraform provider(s) and version
     terraform {
       required_providers {
         aws = {
           source  = "hashicorp/aws"
           version = "3.53.0" # Please change version that will be used here
         }
         template = {
           source = "hashicorp/template"
           version = "2.2.0" # Please change version that will be used here
         }
       }
     }
    
     # Setup aws region and credentials
     provider "aws" {
       region                  = "ap-southeast-1"
       shared_credentials_file = var.aws_credential_file
       profile                 = var.aws_credential_profile
     }
    
  5. Masih di file /ec2/main.tf, selanjutnya ada beberapa bagian yang dijadikan acuan untuk pembuatan resource EC2.

    Image

    Hal pertama yang dilakukan adalah mengambil data AMI ID untuk ubuntu 20.04. Informasi ini yang nantinya digunakan oleh EC2 sebagai AMI ID.

     # Get latest public ubuntu AMI ID from Parameter Store in chosen region
     data "aws_ami" "ubuntu" {
       most_recent = true
    
       filter {
         name   = "name"
         values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
       }
    
       filter {
         name   = "virtualization-type"
         values = ["hvm"]
       }
    
       owners = ["099720109477"] # Canonical
     }
    

    Selanjutnya saya akan mendeklarasikan sebuah template file user-data yang mengacu ke file /ec2/user-data.sh. File ini digunakan sebagai startup-script atau EC2 user data saat bootstrapping EC2.

     # Reference for EC2 user-data
     data "template_file" "user-data" {
       template = "${file("./user-data.sh")}"
     }
    

    Selanjutnya adalah deklarasi child module yang digunakan. Saya referensikan module "instance_profile" dengan sumber/source dari /modules/iam/

     module "instance_profile" {
       source = "../modules/iam/"
     }
    
  6. Masih melanjut di file /ec2/main.tf. Terakhir saya deklarasikan resource ec2 instance dengan nama "ludes-ubuntu-0". Untuk AMI ID mengacu ke data pada poin sebelumnya, yaitu mengambil AMI ID Ubuntu 20.04. Untuk key pair saya gunakan key pair existing yang sudah ada di AWS. Kemudian ec2 akan mengambil user data dari data template_file user_data yang sudah dideklarasikan di poin sebelumnya. Untuk IAM instance profile akan mengambil dari child module dengan acuan nama instance profile-nya adalah iam-instance-profile-name yang sudah kita deklarasikan di /modules/iam/outputs.tf. Hal hal lain seperti instance type, volume size menggunakan acuan variable di /ec2/variables.tf.

    Image

     # Setup EC2 instance using ubuntu AMI
     resource "aws_instance" "ludes-ubuntu-0" {
       ami                         = data.aws_ami.ubuntu.id
       instance_type               = var.ec2_instance_type
       associate_public_ip_address = true
       key_name                    = "ludes-key-demo-0"
       user_data                   = data.template_file.user-data.rendered
       iam_instance_profile        = module.instance_profile.iam-instance- 
    profile-name
    
       root_block_device {
         volume_size = var.ec2_volume_size
       }
    
       tags = {
         Name = "ludes-ubuntu-0" # Please change name tag here
       }
    
       depends_on = [
         module.instance_profile.iam-instance-profile-name
       ]
     }
    
  7. File berikutnya yang akan kita bahas adalah /ec2/user-data.sh. Pada file ini saya deklarasikan startup script dimana saat bootstrapping EC2, akan dilakukan instalasi aws cli.

    Image

     #!/bin/bash
    
     # Shell script to install aws cli from user data when bootstapping ec2
     # Script will run on user ubuntu
     # Might need to relogin before aws cli can fully functional or you can issued command aws --version to verify
     sudo -u ubuntu
     sudo apt-get update
     sudo apt-get install -y unzip
     curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
     unzip awscliv2.zip
     sudo ./aws/install
    
  8. Selanjutnya kita akan bahas file /ec2/variables.tf. Disini sudah saya deklarasikan variable "aws_credential_file" yang menjadi acuan dimana lokasi aws credentials dan variable "aws_credential_profile" akan mengacu ke named profile yang digunakan, dimana pada artikel ini adalah "ludes-terraform-admin". Selain itu juga sudah didefinisikan variable "ec2_instance_type" untuk tipe instance yang digunakan dan "ec2_volume_size" untuk menentukan besarnya volume size EBS yang digunakan EC2.

    Image

     # Define path to aws credentials file
     variable "aws_credential_file" {
       type        = string
       description = "Path to aws credentials file"
       default     = "~/.aws/credentials"
     }
    
     # Define aws profile
     variable "aws_credential_profile" {
       type        = string
       description = "AWS profile used for provision services"
       default     = "ludes-terraform-admin"
     }
    
     # Define EC2 instance type
     variable "ec2_instance_type" {
       type        = string
       description = "Amazon EC2 instance type"
       default     = "t2.micro" # Please change ec2 instance type here
     }
    
     # Define EC2 instance volume size
     variable "ec2_volume_size" {
       type        = number
       description = "Amazon EC2 instance volume size"
       default     = 10 # Please change ec2 root volume size here
     }
    
  9. Terakhir kita akan bahas file /ec2/outputs.tf. Di file ini saya mendeklarasikan 1 output "ec2_public_ip". Output ini akan menampilkan public ip yang digunakan oleh EC2 dan akan tampil setelah terraform apply selesai dilakukan.

    Image

     # Generate output of EC2 public IP
     output "ec2_public_ip" {
       value       = aws_instance.ludes-ubuntu-0.public_ip
       description = "Public IP of EC2 instance"
     }
    
  10. Setelah konfigurasi terraform code selesai, selanjutnya kita dapat lakukan inisialisasi awal dengan menggunakan command terraform init di terminal/cli.

    Image

  11. Setelah itu, untuk memastikan terraform kita valid, kita juga dapat menjalankan terraform validate.

    Image

  12. Setelah inisialisasi dan validasi. Selanjutnya kita dapat menjalankan terraform plan untuk mulai mengetahui resource apa saja yang akan dibuat/dijalankan.

    Image

    Karena saya deklarasikan output maka plan juga akan menampilkan setelah apply selesai akan muncul 1 output.

    Image

  13. Jika plan sudah sesuai, selanjutnya kita dapat jalankan terraform apply agar terraform mulai melakukan pembuatan resource/service di AWS.

    Image

    Tunggu hingga apply selesai dan setelah selesai, kita akan melihat output public ip yang digunakan oleh EC2.

    Image

  14. Selanjutnya coba verifikasi EC2 dengan cara SSH ke IP Public yang tampil pada terraform output.

    Image

  15. Pastikan SSH berhasil dan sudah berhasil masuk ke Ubuntu EC2. Pastikan juga aws cli berhasil terinstall.

    Image

  16. Sampai sini kita sudah dapat memastikan bahwa terraform sudah berhasil membuat EC2 instance. Kita juga dapat memastikan hal tersebut via Web Console AWS. Dan juga dapat memastikan apakah IAM role juga sudah berhasil dibuat.

    Image

    Image

  17. Selanjutnya kita dapat memastikan apakah betul EC2 IAM Role/IAM Instance Profile sudah dapat berjalan dengan semestinya atau belum. Karena di code kita deklarasikan policy AmazonEC2FullAccess, kita dapat coba dengan cara list/describe instance dari Ubuntu EC2.

    Image

  18. Untuk memastikan apakah policy AmazonS3FullAccess yang sudah di-associate juga sudah berjalan dari EC2 Ubuntu atau belum, saya sebelumnya juga sudah membuat S3 bucket dengan nama "ludes-demo-bucket-0".

    Image

  19. Kita dapat pastikan dengan mencoba list s3 bucket via aws cli dari Ubuntu EC2.

    Image

Kesimpulan

Akhirnya kita sampai di penghujung artikel ini. Pada artikel ini kita mencoba membuat EC2 IAM Role/IAM Instance Profile menggunakan IaC tool yaitu Terraform. Kemudian EC2 IAM Role tersebut di associate ke sebuah EC2 Instance. Kita juga sudah memverifikasi bahwa EC2 instance sudah dapat melakukan perintah aws cli sesudah dengan policy yang diizinkan atau di-allow oleh EC2 IAM Role.

File contoh template terraform juga dapat dilihat di github saya: lanandra/terraform-template-aws.

Sekian artikel kali ini. Jika ada saran, masukan atau kritik silahkan tinggalkan pesan di kolom komentar.

Semoga bermanfaat dan terima kasih.

Tinggalkan Balasan

Isikan data di bawah atau klik salah satu ikon untuk log in:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout /  Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout /  Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout /  Ubah )

Connecting to %s

Situs yang Didukung WordPress.com.

Atas ↑

%d blogger menyukai ini: