Ngày 21 - Tự động rà quét image repository
Tự động rà quét image repository
Nội dung
- 90 Ngày DevOps v2 ♾️
- Ngày 1 - Nhìn lại
- Ngày 2 - Bức Tranh Toàn Cảnh: DevSecOps
- Ngày 3 - Tư Duy Như Một Kẻ Tấn Công
- Ngày 4 - Đội Đỏ và Đội Xanh
- Ngày 5 - Bảo Mật Mã Nguồn Mở
- Ngày 6 - Thực Hành Xây Dựng Một Ứng Dụng Có Lỗ Hổng
- Ngày 7: Tổng quan về Lập trình an toàn
- Ngày 8: Tổng quan về SAST
- Ngày 9: Triển khai SAST với SonarCloud
- Ngày 10: Tổng quan về Phân tích Thành phần Phần mềm
- Ngày 11: Triển khai SCA với OWASP Dependency Check
- Ngày 12: Các nguyên tắc lập trình an toàn
- Ngày 13: Các nguyên tắc lập trình an toàn bổ sung
- Ngày 14: Quét container image
- Ngày 15: Quét container image nâng cao
- Ngày 16: Kiểm thử Fuzzing
- Ngày 17: Kiểm thử Fuzzing nâng cao
- Ngày 18: DAST
- Ngày 19: IAST
- Ngày 20: Thực hành với IAST và DAST
- Ngày 21 - Tự động rà quét image repository
Nội dung khoá học
- 90 Ngày DevOps v2 ♾️
- Ngày 1 - Nhìn lại
- Ngày 2 - Bức Tranh Toàn Cảnh: DevSecOps
- Ngày 3 - Tư Duy Như Một Kẻ Tấn Công
- Ngày 4 - Đội Đỏ và Đội Xanh
- Ngày 5 - Bảo Mật Mã Nguồn Mở
- Ngày 6 - Thực Hành Xây Dựng Một Ứng Dụng Có Lỗ Hổng
- Ngày 7: Tổng quan về Lập trình an toàn
- Ngày 8: Tổng quan về SAST
- Ngày 9: Triển khai SAST với SonarCloud
- Ngày 10: Tổng quan về Phân tích Thành phần Phần mềm
- Ngày 11: Triển khai SCA với OWASP Dependency Check
- Ngày 12: Các nguyên tắc lập trình an toàn
- Ngày 13: Các nguyên tắc lập trình an toàn bổ sung
- Ngày 14: Quét container image
- Ngày 15: Quét container image nâng cao
- Ngày 16: Kiểm thử Fuzzing
- Ngày 17: Kiểm thử Fuzzing nâng cao
- Ngày 18: DAST
- Ngày 19: IAST
- Ngày 20: Thực hành với IAST và DAST
- Ngày 21 - Tự động rà quét image repository
Mục lục
Quét Kho lưu trữ Image Liên tục
Trong Ngày 14, chúng ta đã tìm hiểu về quét image container là gì và tại sao nó lại quan trọng. Chúng ta cũng đã biết về các công cụ như Grype và Trivy giúp chúng ta quét các image container của mình.
Tuy nhiên, trong các Vòng đời Phát triển Phần mềm (SDLC) hiện đại, một kỹ sư DevSecOps hiếm khi quét image container thủ công, ví dụ, họ sẽ không chạy Grype và Trivy trên máy cục bộ và xem xét từng lỗ hổng một. Thay vào đó, họ sẽ cấu hình việc quét image như một phần của đường ống CI/CD. Bằng cách này, họ sẽ chắc chắn rằng tất cả các image đang được xây dựng bởi các đường ống cũng được quét bởi trình quét image. Các kết quả này sau đó có thể được gửi đến một hệ thống khác, nơi các kỹ sư DevSecOps có thể xem xét chúng và thực hiện hành động tùy thuộc vào kết quả.
Một đường ống CI/CD mẫu có thể trông như thế này:
- Lập trình viên đẩy code
- Lint code (Kiểm tra định dạng code)
- Build code (Xây dựng code)
- Test code (Kiểm thử code)
- Build các tạo tác (image container, helm chart, v.v.)
- Quét các tạo tác
- (Tùy chọn) Gửi kết quả quét đến một nơi nào đó
- (Tùy chọn) Xác minh kết quả quét và làm thất bại đường ống nếu việc xác minh không thành công
- Đẩy các tạo tác lên một kho lưu trữ
Một lỗi trong các bước quét hoặc xác minh (bước 6 và 7) sẽ có nghĩa là container của chúng ta sẽ không được đẩy lên kho lưu trữ, và chúng ta không thể sử dụng code mà chúng ta đã gửi.
Hôm nay, chúng ta sẽ xem xét cách chúng ta có thể thiết lập một đường ống như vậy và một cấu hình hợp lý cho nó sẽ như thế nào.
Thiết lập đường ống CI/CD với Grype
Hãy cùng xem trình quét Grype. Grype là một trình quét mã nguồn mở được duy trì bởi công ty Anchore.
Quét một image bằng Grype
Việc quét một image container với Grype đơn giản như chạy lệnh sau:
grype <IMAGE>
Ví dụ, nếu chúng ta muốn quét image ubuntu:20.04
, chúng ta có thể chạy:
$ grype ubuntu:20.04
✔ Vulnerability DB [no update available]
✔ Pulled image
✔ Loaded image
✔ Parsed image
✔ Cataloged packages [92 packages]
✔ Scanned image [19 vulnerabilities]
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
coreutils 8.30-3ubuntu2 deb CVE-2016-2781 Low
gpgv 2.2.19-3ubuntu2.2 deb CVE-2022-3219 Low
libc-bin 2.31-0ubuntu9.9 deb CVE-2016-20013 Negligible
libc6 2.31-0ubuntu9.9 deb CVE-2016-20013 Negligible
# ... (kết quả được rút gọn)
Tất nhiên, bạn đã biết điều này vì chúng ta đã làm nó vào Ngày 14.
Tuy nhiên, lệnh này sẽ chỉ xuất ra các lỗ hổng và thoát với mã thành công. Vì vậy, nếu điều này nằm trong một đường ống CI/CD, đường ống sẽ thành công ngay cả khi chúng ta có nhiều lỗ hổng.
Người chạy đường ống sẽ phải mở nó ra, xem nhật ký và tự xác định xem kết quả có ổn không. Điều này rất tẻ nhạt và dễ gây ra lỗi.
Hãy xem cách chúng ta có thể thực thi một số quy tắc cho các kết quả từ quá trình quét.
Thực thi quy tắc cho các image được quét
Như chúng ta đã xác định, chỉ quét image thôi thì không làm được gì nhiều ngoài việc cho chúng ta thấy số lượng lỗ hổng bên trong image. Nhưng nếu chúng ta muốn thực thi một bộ quy tắc cho các image container của mình thì sao?
Ví dụ, một quy tắc tốt sẽ là "một image không nên có các lỗ hổng nghiêm trọng (critical)" hoặc "một image không nên có các lỗ hổng đã có bản vá."
May mắn cho chúng ta, đây cũng là điều mà Grype hỗ trợ sẵn. Chúng ta có thể sử dụng cờ --fail-on <SEVERITY>
để yêu cầu Grype thoát với mã thoát khác không nếu trong quá trình quét, nó tìm thấy các lỗ hổng có mức độ nghiêm trọng cao hơn hoặc bằng mức chúng ta đã chỉ định. Điều này sẽ làm thất bại đường ống của chúng ta, và kỹ sư sẽ phải xem xét kết quả và sửa chữa một cái gì đó để nó có thể vượt qua.
Hãy thử xem. Chúng ta sẽ sử dụng image springio/petclinic:latest
, mà chúng ta đã phát hiện có nhiều lỗ hổng. Bạn có thể quay lại Ngày 14 hoặc tự quét để xem chính xác là bao nhiêu.
Chúng ta muốn làm thất bại đường ống nếu image có các lỗ hổng CRITICAL
. Chúng ta sẽ chạy quét như sau:
$ grype springio/petclinic:latest --fail-on critical
✔ Vulnerability DB [no update available]
✔ Loaded image
✔ Parsed image
✔ Cataloged packages [212 packages]
✔ Scanned image [168 vulnerabilities]
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
spring-core 5.3.6 java-archive CVE-2016-1000027 Critical
spring-core 5.3.6 java-archive CVE-2022-22965 Critical
...
1 error occurred:
* discovered vulnerabilities at or above the severity threshold
$ echo $?
1
Chúng ta thấy hai điều ở đây:
- Ngoài các kết quả, Grype cũng xuất ra một lỗi cho chúng ta biết rằng lần quét này đã vi phạm quy tắc chúng ta đã xác định (không có lỗ hổng CRITICAL)
- Grype thoát với mã thoát 1, cho biết thất bại. Nếu đây là một đường ống CI, nó sẽ bị thất bại.
Khi điều này xảy ra, chúng ta sẽ bị chặn không thể hợp nhất code và đẩy container của mình lên registry. Điều này có nghĩa là chúng ta cần phải hành động để khắc phục lỗi để có thể hoàn thành nhiệm vụ và đẩy thay đổi của mình.
Hãy xem các lựa chọn của chúng ta là gì.
Sửa lỗi đường ống
Khi chúng ta gặp phải một lỗ hổng đang ngăn cản chúng ta phát hành container, chúng ta có một vài cách để xử lý tùy thuộc vào lỗ hổng đó.
1. Lỗ hổng đã có bản vá
Trường hợp tốt nhất là khi lỗ hổng này đã được khắc phục trong một phiên bản mới hơn của thư viện mà chúng ta đang phụ thuộc.
Một lỗ hổng như vậy là đây:
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
snakeyaml 1.27 1.31 java-archive GHSA-3mc7-4q67-w48m High
Đây là một lỗ hổng có mức độ nghiêm trọng High
. Nó đến từ gói Java snakeyaml
, phiên bản 1.27
. Grype đang cho chúng ta biết rằng lỗ hổng này đã được khắc phục trong phiên bản 1.31
của cùng thư viện đó.
Trong trường hợp này, chúng ta chỉ cần nâng cấp phiên bản của thư viện này trong tệp pom.xml
hoặc build.gradle
của mình, kiểm thử code để đảm bảo không có gì bị hỏng với phiên bản mới, và gửi lại code.
Điều này sẽ xây dựng một phiên bản mới của container, quét lại nó, và hy vọng lần này, lỗ hổng sẽ không xuất hiện, và quá trình quét của chúng ta sẽ thành công.
2. Lỗ hổng chưa có bản vá, nhưng không nguy hiểm
Đôi khi một lỗ hổng chúng ta gặp phải sẽ không có bản vá sẵn có. Đây là những lỗ hổng được gọi là lỗ hổng zero-day, được tiết lộ trước khi có bản vá.
Chúng ta có thể thấy hai trong số đó trong kết quả quét ban đầu:
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
spring-core 5.3.6 java-archive CVE-2016-1000027 Critical
spring-core 5.3.6 java-archive CVE-2022-22965 Critical
Khi gặp phải một lỗ hổng như vậy, chúng ta cần đánh giá mức độ nghiêm trọng của nó và tính toán rủi ro khi phát hành phần mềm của mình với lỗ hổng đó.
Chúng ta có thể xác định rằng lỗ hổng không gây ra bất kỳ nguy hiểm nào cho phần mềm và người tiêu dùng của chúng ta. Một trường hợp như vậy có thể là khi một lỗ hổng đòi hỏi quyền truy cập vật lý vào máy chủ để bị khai thác. Nếu chúng ta chắc chắn rằng các máy chủ vật lý của mình đủ an toàn và kẻ tấn công không thể truy cập vào chúng, chúng ta có thể bỏ qua lỗ hổng này một cách an toàn.
Trong trường hợp này, chúng ta có thể yêu cầu Grype bỏ qua lỗ hổng này và không làm thất bại quá trình quét vì nó.
Chúng ta có thể làm điều này thông qua tệp cấu hình grype.yaml
, nơi chúng ta có thể liệt kê các lỗ hổng muốn bỏ qua:
ignore:
# Đây là bộ đầy đủ các trường quy tắc được hỗ trợ:
- vulnerability: CVE-2016-1000027
fix-state: unknown
package:
name: spring-core
version: 5.3.6
type: java-archive
# Chúng ta có thể liệt kê bao nhiêu cái tùy thích
- vulnerability: CVE-2022-22965
# Hoặc liệt kê toàn bộ các gói mà chúng ta muốn bỏ qua
- package:
type: gem
Đặt điều này vào tệp cấu hình của chúng ta và chạy lại quá trình quét sẽ làm cho đường ống của chúng ta chuyển sang màu xanh (thành công).
Tuy nhiên, điều quan trọng là chúng ta phải theo dõi tệp này và không bỏ qua các lỗ hổng đã có bản vá. Ví dụ, khi một bản vá cho lỗ hổng này được phát hành, tốt nhất là chúng ta nên nâng cấp phụ thuộc của mình và loại bỏ lỗ hổng này khỏi ứng dụng.
Bằng cách đó, chúng ta sẽ đảm bảo rằng ứng dụng của mình an toàn nhất có thể và không có lỗ hổng nào có thể trở nên nghiêm trọng hơn chúng ta nghĩ ban đầu.
3. Lỗ hổng chưa có bản vá, và NÓ nguy hiểm
Trường hợp xấu nhất là nếu chúng ta gặp phải một lỗ hổng chưa có bản vá, và nó thực sự nguy hiểm, và có khả năng bị khai thác.
Trong trường hợp đó, không có một nước đi nào là hoàn toàn đúng. Điều tốt nhất chúng ta có thể làm là ngồi lại với đội ngũ bảo mật và đưa ra một kế hoạch hành động.
Chúng ta có thể quyết định tốt nhất là không làm gì trong khi chờ lỗ hổng được vá. Chúng ta có thể quyết định vá một số thứ thủ công để loại bỏ ít nhất một phần nguy hiểm. Nó thực sự phụ thuộc vào tình hình.
Đôi khi, một lỗ hổng zero-day đã có trong ứng dụng đang được triển khai của bạn. Trong trường hợp đó, việc đóng băng các lần triển khai sẽ không giúp ích gì vì ứng dụng của bạn đã dễ bị tấn công.
Đó là trường hợp của lỗ hổng Log4Shell được phát hiện vào cuối năm 2021 nhưng đã tồn tại trong Log4j từ năm 2013. May mắn thay, đã có một bản vá trong vòng vài giờ, nhưng lần sau chúng ta có thể không may mắn như vậy.
Tóm tắt
Như chúng ta đã học trong Ngày 14, việc quét các image container để tìm lỗ hổng là rất quan trọng vì nó có thể cung cấp cho bạn những hiểu biết quý giá về tình hình bảo mật của các image.
Hôm nay chúng ta đã học được rằng việc tích hợp nó như một phần của đường ống CI/CD và thực thi một số quy tắc cơ bản về các lỗ hổng bạn có trong image của mình còn tốt hơn nữa.
Cuối cùng, chúng ta đã thảo luận về các bước chúng ta có thể thực hiện khi tìm thấy một lỗ hổng.
Ngày mai, chúng ta sẽ xem xét các registry container cho phép quét tự động và cũng sẽ xem xét việc quét các loại tạo tác khác.
Hẹn gặp lại bạn vào ngày 22.
Các bài viết là bản tiếng Việt của tài liệu 90DaysOfDevOps của Micheal Cade và có qua sửa đổi, bổ sung. Tất cả đều có license [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License][cc-by-nc-sa].