+19

Terraform Series - Bài 17 - Security - Securing Logs and Securing State File

Bài viết gốc - Bài 17 - Securing Logs and Securing State File

Chào các bạn tới với series về Terraform, ở bài trước chúng ta đã tìm hiểu về Multi Cloud. Ở bài tiếp theo này chúng ta sẽ tìm hiểu về một chủ đề rất quan trọng là bảo mật trong Terraform. Ta sẽ quản lý những thông tin nhạy cảm trong Terraform như thế nào?

image.png

Khi ta dùng Terraform để quản lý và tạo hạ tầng cho môi trường production, thì đối với các resource như Database, Redis, Bastion Host, thông tin để truy cập được những thằng này là thông tin nhạy cảm và cần bảo mật. Và nếu bạn để ý thì sẽ thấy là toàn bộ những bài ta đã làm trong series này, dữ liệu của hạ tầng của ta đều được lưu trữ trong state file ở dạng plain text. Có nghĩa là nếu ai truy cập được state file này thì đều có thể thấy được những thông tin nhạy cảm của ta.

Nên ở bài này chúng ta sẽ học cách làm sao để bảo mật được những dữ liệu nhạy cảm đã nói ở trên. Ta sẽ tìm hiểu:

  • Securing logs.
  • Securing state files.
  • Dynamic secrets.
  • Sentinel (policy as code).

Securing logs

Thứ đầu tiên có thể lộ thông tin bảo mật là logs, khi bạn chạy câu lệnh terraform plan hoặc terraform apply, những thứ in ra terminal sẽ được lưu vào file log ở thư mục /tmp (linux) trong một khoảng thời gian.

Sensitive Variable

Nếu trong lúc terraform chạy apply mà ta có in ra thông tin gì nhạy cảm thì nó sẽ bị lộ nếu ai truy cập được vào máy bạn. Ví dụ nếu ta dùng local-exec như sau:

resource "null_resource" "print" {
  provisioner "local-exec" {
    command = <<-EOF
      echo "username = ${var.postgres_username}"
      echo "password = ${var.postgres_password}"
    EOF
  }
}

Khi ta chạy câu lệnh terraform apply thì log nó sẽ in ra như sau:

...
null_resource.uh_oh (local-exec): username=secret-username
null_resource.uh_oh (local-exec): password=secret-password
null_resource.uh_oh: Creation complete after 0s [id=5973892021553480485]
...

Thông in bảo mật của ta sẽ lưu vào trong log, nên khi ta sử dụng variable trong Terraform thì những biến chứa thông tin nhạy cảm ta nên thêm một trường cho nó là sensitive, ví dụ:

variable "postgres_username" {
  type = string
  sensitive = true
}

variable "postgres_password" {
  type = string
  sensitive = true
}

resource "null_resource" "print" {
  provisioner "local-exec" {
    command = <<-EOF
      echo "username = ${var.postgres_username}"
      echo "password = ${var.postgres_password}"
    EOF
  }
}

Khi ta chạy apply thì nó sẽ được in ra terminal như sau:

...
null_resource.uh_oh (local-exec): (output suppressed due to sensitive value in config)
null_resource.uh_oh (local-exec): (output suppressed due to sensitive value in config)
null_resource.uh_oh: Creation complete after 0s [id=5973892021553480485]
...

Dangers of TF_LOG=trace

Khi bạn chạy apply với TF_LOG=trace thì ta sẽ thấy có rất nhiều thông tin được in ra.

export TF_LOG=trace
terraform apply

Thông tin nó in ra như sau:

...
Trying to get account information via sts:GetCallerIdentity
[aws-sdk-go] DEBUG: Request sts/GetCallerIdentity Details:
---[ REQUEST POST-SIGN ]-----------------------------
POST / HTTP/1.1
Host: sts.amazonaws.com
User-Agent: aws-sdk-go/1.30.16 (go1.13.7; darwin; amd64) APN/1.0
HashiCorp/1.0 Terraform/0.12.24 (+https://www.terraform.io)
Content-Length: 43
Authorization: AWS4-HMAC-SHA256 Credential=AKIATESI2XGPMMVVB7XL/20200504/us-east-1/sts/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date, Signature=c4df301a200eb46d278ce1b6b9ead1cfbe64f045caf9934a14e9b7f8c207c3f8
Content-Type: application/x-www-form-urlencoded; charset=utf-8
...

Bạn sẽ thấy có một thông tin rất quan trọng ở phần Authorization, đây là token được lấy từ AWS STS, thông tin này ta có thể dùng để gọi API lên AWS. Nếu bạn dùng AWS IAM với quyền admin thì càng nguy hiểm hơn, tuy rằng token này chỉ tồn tại trong vòng 15 phút nhưng cũng khá nguy hiểm. Nên bạn chỉ nên dùng TF_LOG=trace khi thực sự cần debug.

Securing state files

Terraform được sinh ra với mục đích là quản lý và cung cấp hạ tầng thông qua state file, nó sẽ không quan tâm là những thông tin được lưu trữ trong state file có phải là thông tin nhạy cảm hay không và nó cũng không có quá nhiều tính năng để làm điều đó. Nên để bảo mật được những dữ liệu trong state file, ta phải tìm những phương pháp khác, đây là một số cách để ta có thể bảo mật dữ liệu trong state file.

Removing unnecessary secrets from Terraform

Mặc dù chúng ta không thể mã hóa thông tin bảo mật ở trong state file, nhưng ta có thể xóa bớt những thông tin được coi là nhạy cảm nhiều nhất có thể khi ta viết file code cho Terraform.

Fewer secrets means you have less to lose in the event of a data breach

Cách bảo mật tốt nhất là ta càng có càng ít thông tin cần được bảo mật thì càng tốt :))). Trong Terraform chỉ có ba configuration blocks sau là sẽ lưu trữ thông tin trong state file: resources, data sources, và output values. Còn các blocks khác như providers, input variables, local values, ... thì sẽ không được lưu trong state file.

Nên đối với các giá trị mà sẽ không lưu thông tin vào trong state file, thì thay vì fix cứng giá trị trong code, thì ta nên để nó trong biến môi trường và truyền vào khi ta chạy câu lệnh apply, ví dụ như sau, thay vì để giá trị trong code.

provider "aws" {
  region     = var.region
  access_key = "ABCXYZ"
  secret_key = "ABCXYZ"
}

Thì ta nên dùng như sau.

provider "aws" {
  region     = var.region
  access_key = var.access_key
  secret_key = var.secret_key
}
terraform apply -var="access_key=ABCXYZ" -var="secret_key=ABCXYZ"

Nhưng với những blocks mà lưu dữ liệu vào trong state file như resources thì cho dù ta có dùng biến môi trường thì nó vẫn được lưu vào trong state file, ví dụ.

resource "aws_rds_cluster" "postgres" {
  cluster_identifier = "postgres"
  engine             = "aurora-postgresql"
  engine_mode        = "provisioned"
  engine_version     = "13.6"
  database_name      = "terraform"
  master_username    = var.username
  master_password    = var.password
}

Thì khi ta tạo resource này, ta kiểm tra trong state file thì vẫn thấy giá trị của nó vẫn được lưu ở dạng plain text.

...
 {
      "mode": "managed",
      "type": "aws_db_instance",
      "name": "postgres",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "schema_version": 1,
          "attributes": {
          ...
            "nchar_character_set_name": "",
            "option_group_name": "default:postgres-12",
            "parameter_group_name": "custom-postgres12",
            "password": "secret-password", // plain text
            ...
            "username": "secret-username", // plain text
            ...
          ...
          }
       ]
       ...
}
...

Như bạn thấy thì thông tin password vẫn được lưu trong state file ở dạng plain text, không có mã hóa gì hết, nên để bảo mật những thông tin thế này, thì ta nên làm theo phương pháp tiếp theo đây.

Terraform Backend and Least-privileged access control

Sử dụng biến môi trường đối với các blocks mà không được lưu trong state file, còn với các blocks khác ta không thể ngăn chặn được việc nó được lưu vào trong state file theo dạng plain text, thì thay vào đó ta nên sử dụng Terraform Backend để lưu state file ở một chỗ có thể coi là rất bảo mật, và ta có thể cho phép ai mới được vào đó để đọc state file.

Ví dụ như là ta dùng S3 Standard Backend , lúc này thì state file của ta sẽ được lưu trên AWS S3.

image.png

Và với AWS thì nó đã cung cấp cho ta sẵn một bộ phân quyền cho S3, chỉ có ai ta cho phép thì họ mới có thể vào xem được, nên lúc này thì dữ liệu của ta có được lưu ở dạng plain text cũng không có vấn đề lắm, vì ta kiểm soát được việc ai mới có quyền để xem.

Encryption at rest

Encryption at rest là cách để ta mã hóa dữ liệu và chuyển nó thành một dạng mà con người không thể đọc hiểu được, và chỉ có người đã mã hóa mới biết nó là gì.

image.png

Hầu hết các loại Terraform Backend đều có Encryption at rest, ví dụ đối với S3 thì nó có cung cấp cho ta khá nhiều phương pháp để mã hóa.

Kết luận

Vậy là ta đã tìm hiểu xong những vấn đề bảo mật ta có thể gặp phải và cách khắc phục nó, những ý quan trọng là ta nên sử dụng sensitive cho các biến secret, và dữ liệu sẽ được lưu trong state file ở dạng plain text, do đó ta nên sử dụng Terraform Backend và ta có thể kiểm soát người nào mới có thể truy cập được state file của ta. Nếu có thắc mắc hoặc cần giải thích rõ thêm chỗ nào thì các bạn có thể hỏi dưới phần comment.

DevOps VN

Học DevOps tại các trung tâm uy tín.

Kiến thức dinh dưỡng IT.

Ủng hộ trang tại đây.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.