DevSecOps และ CI/CD คู่หูที่ขาดไม่ได้ในการพัฒนาซอฟต์แวร์ที่ปลอดภัย

ก่อนจะลงลึกใน DevSecOps สิ่งสำคัญคือต้องเข้าใจแนวคิดพื้นฐานของ DevOps กันก่อน DevOps คือการเคลื่อนไหวทางวัฒนธรรมและเทคนิคที่ผสมผสานปรัชญา แนวทางปฏิบัติ และเครื่องมือต่างๆ เข้าด้วยกัน เพื่อเพิ่มความสามารถขององค์กรในการส่งมอบแอปพลิเคชันและบริการด้วยความเร็วและประสิทธิภาพสูง

ในโลกของการพัฒนาซอฟต์แวร์ที่เปลี่ยนแปลงอย่างรวดเร็ว ความปลอดภัยมักจะถูกละเลย ทำให้เกิดช่องโหว่และการละเมิดที่อาจเกิดขึ้นได้ เพื่อลดความเสี่ยงเหล่านี้ การบูรณาการความปลอดภัยเข้ากับกระบวนการ DevOps ถือเป็นสิ่งสำคัญ นี่คือจุดที่ DevSecOps เข้ามามีบทบาท

DevSecOps คืออะไร?

DevSecOps เป็นตัวแทนของการเปลี่ยนแปลงทางวัฒนธรรมที่สมาชิกในทีมทุกคนที่เกี่ยวข้องกับการพัฒนาแอปพลิเคชันให้ความสำคัญกับความปลอดภัยตลอดวงจรชีวิตการพัฒนาซอฟต์แวร์ (SDLC) DevSecOps มุ่งมั่นที่จะนำแนวทางปฏิบัติด้านความปลอดภัยเข้ามาใช้ในแต่ละขั้นตอนของการพัฒนา เพื่อให้แน่ใจว่าความปลอดภัยไม่ใช่เพียงแค่สิ่งที่คิดขึ้นทีหลังแต่เป็นองค์ประกอบพื้นฐานของกระบวนการ การบูรณาการนี้เกี่ยวข้องกับการนำการตรวจสอบความปลอดภัยที่จำเป็นมาใช้ภายในระบบอัตโนมัติ Continuous Integration และ Continuous Deployment (CI/CD) ซึ่งได้รับการสนับสนุนจากเครื่องมือที่เหมาะสม

ประโยชน์จากการใช้ DevSecOps คืออะไร?

  • ค้นหาช่องโหว่และจุดบกพร่องในระยะเริ่มต้นของการพัฒนา
  • ปฏิบัติตามข้อกำหนดอย่างมีประสิทธิภาพ
  • กู้คืนข้อมูลได้อย่างรวดเร็ว
  • มีความปลอดภัยทั้งกระบวนการพัฒนา
  • ประหยัดต้นทุน
  • ลดความเสี่ยงของการโจมตีจากภายนอกและเพิ่มความมั่นใจ
  • มองเห็นภัยคุกคามที่อาจเกิดขึ้นได้อย่างชัดเจนและวิธีแก้ไขที่เป็นไปได้

Gitlab-ci DevSecOps pipeline

ตัวอย่าง Gitlab-ci pipeline

ในครั้งนี้ผมจะกล่าวถึงขั้นตอน CI/CD พื้นฐานต่อไปนี้ และวิธีการรักษาความปลอดภัยตั้งแต่ตอน Code ไปจนถึง Deploy เพื่อให้เข้าใจมากขึ้น โดยจะยังไม่พูดถึงขั้นตอน Monitor&Alert

DevSecOps Flow
  1. Develop
  2. Merge request
  3. Build และ Code analysis
  4. Test
  5. Deploy

1) Develop

ขั้นตอนการพัฒนาเริ่มต้นด้วยการเขียนโค้ด และเราสามารถใช้ทำให้ปลอดภัยได้ตั้งแต่ขั้นตอนนี้เลย ถ้าตามรูป DevSecOps Flow ด้านบนจะอยู่ในส่วนของ vs-code และ pre-commit โดยจะขั้นตอนดังนี้

  • ติดตั้งเครื่องมือตรวจสอบข้อผิดพลาดภายในตัวแก้ไขโค้ด เช่น Visual Studio Code หนึ่งในเครื่องมือตรวจสอบข้อผิดพลาดที่ได้รับความนิยมมากที่สุดคือ SonarLint ซึ่งจะเน้นที่จุดบกพร่องและช่องโหว่ด้านความปลอดภัยขณะที่คุณเขียนโค้ด
  • ใช้ Pre-commit hooks เพื่อป้องกันการเพิ่มความลับใดๆ ลงในโค้ด
  • ตั้งค่า Protect branch สำหรับ branch สำคัญๆ
ตรวจสอบคุณภาพโค้ดก่อน commit ด้วย pre-commit
ในการพัฒนาซอฟต์แวร์ คุณภาพของโค้ดเป็นสิ่งสำคัญอย่างยิ่ง โค้ดที่ดีควรเป็นไปตามมาตรฐานที่กำหนด ผ่านการทดสอบ และปราศจากข้อผิดพลาด หากโค้ดมีคุณภาพดีก็จะทำให้การพัฒนาซอฟต์แวร์เป็นไปอย่างราบรื่น และลดปัญหาที่อาจเกิดขึ้นในอนาคต หนึ่งในเครื่องมือที่ผมนำมาใช้พัฒนาโค้ดให้มีคุ

2) Merge Request

โดยปกตินักพัฒนาจะไม่มีสิทธิ์ในการนำโค้ดเข้าไปยัง Branch หลัก และจำเป็นต้องมีการสร้าง Merge request เพื่อส่งคำขอไปยัง Tech lead ให้มาตรวจโค้ดก่อน เมื่อผ่านจึงจะปล่อยให้ Merge ลงไปยัง branch หลักได้

ซึ่งในขั้นตอนนี้เราก็จะเอา CI/CD มาช่วยในการแสกนหา Secret key ต่าง ๆ และจัดระเบียบโค้ดให้เรียบร้อยก่อน

2.1 Gitleaks

จะมาช่วยในการตรวจจับและป้องกันรหัสผ่านลับ, คีย์ API, โทเค็น, คีย์ส่วนตัว ฯลฯ ที่อยู่ในโค้ด ไม่ให้นำขึ้นมา

Gitlab-ci กล้วยๆ: ใช้ Gitleaks ตรวจจับและป้องกัน secret key ไม่ให้เข้ามาในโค็ด
ในการพัฒนาซอฟแวร์ต่างๆ เรามีความจำเป็นต้องใช้งานพวก secret key หรือรหัสผ่านต่างๆ เพื่อเข้าถึงฐานข้อมูล หรือเข้าถึงระบบต่างๆ จากผู้ให้บริการที่อื่น ซึ่งโดยปกติเราจะทำกันในรูปแบบ .env เพื่อเรียกค่ามาใช้งาน และไม่ควรเขียนรหัสผ่าน หรื

2.2 Code lint

จะมาช่วยจัดระเบียบโค้ดให้เรียบร้อย โดยส่วนใหญ่จะใช้ Lint ของภาษานั้น ๆ เช่น eslint, Golang CI Lint เป็นต้น

eslint:
  stage: test
  dependencies: []
  script:
    - npm ci
    - npm run lint
  cache:
    paths:
      - node_modules

ตัวอย่าง eslint ใน gitlab-ci

3) Build และ Code analysis

ก่อน build เราจำเป็นต้องสแกนโค้ดของเราเพื่อหาช่องโหว่ต่าง ๆ เพื่อเป็นการป้องกันเบื้องต้นก่อนจะโดยเจาะระบบในภายหลัง

3.1 Dockerfile static scanning

จะทำการตัวสอบ Dockerfile ที่เราเขียนไว้ว่าได้เขียนถูกต้องการหลัก best practices แล้วหรือไม่

dockerfile_scan:
  stage: scan
  image:
    name: bridgecrew/checkov:latest
    entrypoint:
      - "/usr/bin/env"
      - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
  script:
    - checkov -d . --framework dockerfile --compact
  rules:
    - if: $CI_COMMIT_BRANCH == 'dev'
      exists:
        - "**/Dockerfile"

ตัวอย่าง dockerfile scan ใน gitlab-ci

3.2 SAST

เป็นขั้นตอนการทำ SAST (Static Application Security Testing) เพื่อดูว่าเราเขียนโค้ดได้อย่างปลอดภัยหรือไม่

Gitlab-ci กล้วยๆ: Bearer เครื่องมือ SAST ฟรีสุดล้ำ สแกนหาช่องโหว่ในโค้ดของเราได้ทุกเวลา
สมัยนี้อะไรๆ ก็ต้องปลอดภัยไว้ก่อนโดยเฉพาะโค็ดของเราที่ต้องเน้นย้ำในเรื่องนี้ให้มาก ซึ่งการเขียนโค็ดที่จะให้ปลอดภัยนั้นเราจำเป็นต้องมีเครื่องมือที่จะช่วยบอก และแนะนำในส่วนที่เราเขียนพลาดได้ตลอดเวลา และสำหรับโปรแกรมเมอร์ผู้รักความปลอดภัย! วันนี้จึงอยากขอแนะนำ Bearer CLI เครื

หรือเราจะติดตั้ง SonarQube เพื่อดูเป็นรายงานที่สวยงามก็ได้

ติดตั้ง SonarQube โดย Docker-compose
การรักษาคุณภาพของโค้ดเป็นสิ่งสำคัญสำหรับการพัฒนาซอฟต์แวร์ที่มีประสิทธิภาพและง่ายต่อการบำรุงรักษา SonarQube เป็นเครื่องมือวิเคราะห์คุณภาพโค้ดอัตโนมัติยอดนิยมที่ช่วยค้นพบจุดบกพร่องและแนะนำวิธีปรับปรุงโค้ดให้ดีขึ้น ผมใช้ SonarQube ในฐานะ Code Review
sonar_sast:
  stage: scan
  image:
    name: sonarsource/sonar-scanner-cli:latest
    entrypoint: [""]
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
    GIT_STRATEGY: clone # clone entire repo instead of reusing workspace
    GIT_DEPTH: "0" # avoid shallow clone to give sonar all the info it needs
  cache:
    key: "${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script:
    - sonar-scanner
  allow_failure: true

ตัวอย่างไฟล์ gitlab-ci ในการทำ sonar scan

3.3 Dependency Check

ขั้นตอนนี้จะทำการแสกนตรวจสอบ Dependency ของระบบที่เรานำมาใช้ว่ามีช่องโหว่เกิดขึ้นหรือไม่ หากพบมันจะสร้างรายงานที่เชื่อมโยงไปยังรายการ CVE ที่เกี่ยวข้อง เพื่อให้เราทราบถึงข้อมูลช่องโหว่ล่าสุด

Gitlab-ci กล้วยๆ: หาช่องโหว่ Dependency ให้แอพเราด้วย Trivy
ในการพัฒนาแอพพลิเคชั่นยังไงเราก็จำเป็นต้องใช้งาน Dependency ข้างนอกมาช่วยทำให้ระบบเราทำงานได้ดีขึ้นในหลายๆ เรื่อง แล้วเราจะมั่นใจได้ยังไงว่า Dependency ที่เราเรียกมาใช้นั้น ไม่มีช่องโหว่ (Vulnerability) ที่อาจทำให้ผู้ไม่ประสงค์เข้ามาโจมตี (Hacker) แอพพลิเคชั่นเราผ่านช่องโหว่นั

3.4 Container image scan

เป็นการแสกน Docker image ที่เรา build เสร็จแล้วก่อนนำขึ้นไปเก็บยัง Docker registry จะทำให้ทราบถึงสถานะความปลอดภัยของ Container และช่วยให้เราสามารถดำเนินการต่างๆ ที่ทำให้ Container มีความปลอดภัยมากขึ้น เราควรหลีกเลี่ยงการติดตั้งแพ็คเกจที่ไม่จำเป็นและใช้วิธีการหลายขั้นตอน วิธีนี้จะช่วยให้ Container ปลอดภัย

Gitlab-ci กล้วยๆ: มาแสกน Vulnerability ใน Container Image กัน
คนที่เขียน Dockerfile บรรทัดแรกสุดก็คือ FROM เพื่อดึง Image มาใช้งานใช่ไหม? แล้วเราจะมั่นใจได้ยังไงว่า Image ที่เรานำมาใช้งานปลอดภัยไม่มีช่องโหว่ (Vulnerability) เกิดขึ้น หรือตอนแรกนำมาใช้อาจจะปลอดภัย แต่นานๆ ไปมันจะปลอดภัยเหมือนเดิมไหม เราไม่รู้เลย ดั

4) Test

4.1 Smoke test

Smoke Test คือการทดสอบเบื้องต้นที่ใช้ตรวจสอบว่าฟังก์ชันหลักของซอฟต์แวร์ทำงานได้ตามที่คาดหวังหรือไม่ โดยมักจะใช้ในขั้นตอนหลังจากการติดตั้งหรือการอัปเดตซอฟต์แวร์ เพื่อให้แน่ใจว่าระบบสามารถทำงานได้โดยไม่มีข้อผิดพลาดที่สำคัญ

4.2 Unitest

เป็นการทดสอบระบบที่ใช้ในการตรวจสอบความถูกต้องของส่วนประกอบเล็กๆ ที่เรียกว่า "ยูนิต" ของระบบ โดยยูนิตนี้มักจะหมายถึงฟังก์ชัน, เมธอด, หรือคลาสในโค้ดของซอฟต์แวร์ ซึ่งการทดสอบนี้ช่วยให้มั่นใจได้ว่าส่วนประกอบเฉพาะนั้นทำงานตามที่คาดหวัง

5) Deploy

หลังจากที่เราตรวจสอบโค้ดของเรามาแล้วทั้งหมด ถ้าผ่านก็สามารถ Deploy ได้เลย ซึ่งการ Deploy ระบบนั้นอยู่ที่ว่าปลายทาง Server ของเราเป็นแบบไหนก็เขียน script ตามนั้น แต่โดยส่วนมากก็อาจจะเป็นการ ssh ไปยัง server เพื่อทำการ Deploy ก็สามารถนำ Gitlab-ci ไปจัดการได้เช่นกัน

ใช้ ssh ไปยัง linux server ที่ต้องการใน Gitlab-ci
สำหรับใครที่ต้องการ ssh ไปยัง linux server ที่ต้องการเพื่อ deploy ระบบ โดยให้มันทำ automation ทั้งหมดผ่าน Gitlab-ci มาดูกันว่ายังไง สร้าง Private key ที่เครื่อง server ไปยัง server ที่ต้องการ deploy ระบบ แล้วทำการสร้าง private key ขึ

สรุป

เพื่อสรุปสิ่งที่เราได้ดำเนินการในการสร้าง DevSecOps Pipeline เราเริ่มต้นด้วยการตรวจสอบ Secret key และการทดสอบความปลอดภัยของโค้ด (SAST) เพื่อค้นหาช่องโหว่ในโค้ดของเรา จากนั้นเราได้ทำการสแกน DockerfileContainer image รวมถึงการทดสอบการตรวจสอบความถูกต้องของ Container เพื่อให้แน่ใจว่ามีความปลอดภัยและเชื่อถือได้ก่อนนำไป Deploy ระบบ

และได้ทำการทดสอบ SmokeUnitest เพื่อยืนยันว่าไม่มีข้อผิดพลาดในระหว่างการติดตั้ง ระบบ ซึ่งเป็นสิ่งสำคัญที่ต้องจดจำว่า ความปลอดภัยต้องการการดูแลและปรับปรุงอย่างต่อเนื่อง อย่างไรก็ตาม นี่เป็นเพียงขั้นตอนแรกในเส้นทางที่ไม่มีที่สิ้นสุดสู่การสร้าง DevSecOps ที่มีประสิทธิภาพ

ก็หวังว่าบทความนี้จะทำให้ผู้ที่จะเริ่มต้น DevSecOps เข้าใจในการทำ Pipeline มากขึ้นว่าควรมีขั้นตอนไหนบ้าง ซึ่งต้องบอกก่อนว่าพอเราเข้าใจแล้ว ก็สามารถไปแก้ไขเป็นของตัวเองได้เลย จะทำ Job ไหนก่อนหลังก็ได้ตามแต่ตกลงกันในทีม...

Thank: https://www.infracloud.io/blogs/implement-devsecops-secure-ci-cd-pipeline