OS ํŒจํ‚ค์ง€ ์ž๋™ ์Šค์บ”

์ด ๋ฌธ์„œ์—์„œ๋Š” Container Scanning API๋ฅผ ์‚ฌ์šฉ ์„ค์ •ํ•˜๊ณ , ์ด๋ฏธ์ง€๋ฅผ Artifact Registry์— ํ‘ธ์‹œํ•˜๊ณ , ์ด๋ฏธ์ง€์—์„œ ๋ฐœ๊ฒฌ๋œ ์ทจ์•ฝ์  ๋ชฉ๋ก์„ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.

Artifact Analysis๋Š” Artifact Registry์˜ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€์— ๋Œ€ํ•œ ์ทจ์•ฝ์  ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋Š” ๋ฉ”๋ชจ๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€์™€ ์—ฐ๊ฒฐ๋œ ๋ฉ”๋ชจ์˜ ๊ฐ ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•œ ์–ด์ปค๋Ÿฐ์Šค๊ฐ€ ์ž‘์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๊ฐœ์š” ๋ฐ ๊ฐ€๊ฒฉ ์ฑ…์ • ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

์ด API๋ฅผ ์‚ฌ์šฉ ์„ค์ •ํ•˜๋ฉด Artifact Registry์—์„œ ์–ธ์–ด ํŒจํ‚ค์ง€ ์Šค์บ”๋„ ์‚ฌ์šฉ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. ์ง€์›๋˜๋Š” ํŒจํ‚ค์ง€ ์œ ํ˜•์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the Artifact Registry and Container Scanning APIs.

    Enable the APIs

  5. Install the Google Cloud CLI.

  6. ์™ธ๋ถ€ ID ๊ณต๊ธ‰์—…์ฒด(IdP)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๋จผ์ € ์ œํœด ID๋กœ gcloud CLI์— ๋กœ๊ทธ์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  7. gcloud CLI๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

    gcloud init
  8. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  9. Verify that billing is enabled for your Google Cloud project.

  10. Enable the Artifact Registry and Container Scanning APIs.

    Enable the APIs

  11. Install the Google Cloud CLI.

  12. ์™ธ๋ถ€ ID ๊ณต๊ธ‰์—…์ฒด(IdP)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๋จผ์ € ์ œํœด ID๋กœ gcloud CLI์— ๋กœ๊ทธ์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  13. gcloud CLI๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

    gcloud init
  14. Artifact Registry์— Docker ์ €์žฅ์†Œ๋ฅผ ๋งŒ๋“ค๊ณ  ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅ์†Œ์— ํ‘ธ์‹œํ•ฉ๋‹ˆ๋‹ค. Artifact Registry์— ์ต์ˆ™ํ•˜์ง€ ์•Š์œผ๋ฉด Docker ๋น ๋ฅธ ์‹œ์ž‘์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.
  15. ์ด๋ฏธ์ง€ ์ทจ์•ฝ์  ๋ณด๊ธฐ

    Artifact Analysis๋Š” ์ƒˆ๋กœ์šด ์ด๋ฏธ์ง€๊ฐ€ Artifact Registry์— ์—…๋กœ๋“œ๋  ๋•Œ ์ด๋ฅผ ์Šค์บ”ํ•ฉ๋‹ˆ๋‹ค. ์ด ์Šค์บ”์€ ์ปจํ…Œ์ด๋„ˆ์˜ ์‹œ์Šคํ…œ ํŒจํ‚ค์ง€์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.

    Google Cloud ์ฝ˜์†”, Google Cloud CLI ๋˜๋Š” Container Analysis API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์˜ ์ด๋ฏธ์ง€์— ๋Œ€ํ•œ ์ทจ์•ฝ์  ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€์— ์ทจ์•ฝ์ ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์„ธ๋ถ€์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Artifact Analysis๋Š” ์ง€๋‚œ 30์ผ ๋™์•ˆ ํ‘ธ์‹œ๋˜๊ฑฐ๋‚˜ ๊ฐ€์ ธ์˜จ ์ด๋ฏธ์ง€์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋งŒ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. 30์ผ์ด ์ง€๋‚˜๋ฉด ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ๋” ์ด์ƒ ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š์œผ๋ฉฐ ๊ฒฐ๊ณผ๊ฐ€ ์˜ค๋ž˜๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ Artifact Analysis๋Š” 90์ผ ๋„˜๊ฒŒ ๋น„ํ™œ์„ฑ ์ƒํƒœ์ธ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๊ด€์ฒ˜๋ฆฌํ•˜๋ฉฐ, ์ด ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋Š” Google Cloud ์ฝ˜์†”, gcloud ๋˜๋Š” API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์˜ค๋ž˜๋˜์—ˆ๊ฑฐ๋‚˜ ๋ณด๊ด€์ฒ˜๋ฆฌ๋œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ์ด๋ฏธ์ง€๋ฅผ ๋‹ค์‹œ ์Šค์บ”ํ•˜๋ ค๋ฉด ํ•ด๋‹น ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค์„ธ์š”. ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•˜๋Š” ๋ฐ ์ตœ๋Œ€ 24์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Google Cloud ์ฝ˜์†”์—์„œ ๋ฐœ์ƒ ๋ณด๊ธฐ

    ์ด๋ฏธ์ง€์˜ ์ทจ์•ฝ์ ์„ ํ™•์ธํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ๋”ฐ๋ฅด์„ธ์š”.

    1. ์ €์žฅ์†Œ ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

      ์ €์žฅ์†Œ ํŽ˜์ด์ง€ ์—ด๊ธฐ

    2. ์ €์žฅ์†Œ ๋ชฉ๋ก์—์„œ ์ €์žฅ์†Œ๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

    3. ์ด๋ฏธ์ง€ ๋ชฉ๋ก์—์„œ ์ด๋ฏธ์ง€ ์ด๋ฆ„์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

      ๊ฐ ์ด๋ฏธ์ง€ ๋‹ค์ด์ œ์ŠคํŠธ์˜ ์ทจ์•ฝ์  ํ•ฉ๊ณ„๊ฐ€ ์ทจ์•ฝ์  ์—ด์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

      ์ทจ์•ฝ์ ์ด ์žˆ๋Š” ์ด๋ฏธ์ง€์˜ ์Šคํฌ๋ฆฐ์ƒท

    4. ์ด๋ฏธ์ง€์˜ ์ทจ์•ฝ์  ๋ชฉ๋ก์„ ๋ณด๋ ค๋ฉด ์ทจ์•ฝ์  ์—ด์— ์žˆ๋Š” ๋งํฌ๋ฅผ ํด๋ฆญํ•˜์„ธ์š”.

      ์Šค์บ” ๊ฒฐ๊ณผ ์„น์…˜์—๋Š” ์Šค์บ”๋œ ํŒจํ‚ค์ง€ ์œ ํ˜•, ์ด ์ทจ์•ฝ์ , ์ˆ˜์ •์‚ฌํ•ญ์ด ์žˆ๋Š” ์ทจ์•ฝ์ , ์ˆ˜์ •์‚ฌํ•ญ์ด ์—†๋Š” ์ทจ์•ฝ์ , ํšจ๊ณผ์ ์ธ ์‹ฌ๊ฐ๋„์˜ ์š”์•ฝ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

      ์ทจ์•ฝ์ , ์ˆ˜์ •์‚ฌํ•ญ, ์œ ํšจ ์‹ฌ๊ฐ๋„๊ฐ€ ํ‘œ์‹œ๋œ ์Šค์บ” ๊ฒฐ๊ณผ ์„น์…˜์˜ ์Šคํฌ๋ฆฐ์ƒท

      ์ทจ์•ฝ์  ํ‘œ์—๋Š” ๋ฐœ๊ฒฌ๋œ ๊ฐ ์ทจ์•ฝ์ ์˜ ๊ณตํ†ต ์ทจ์•ฝ์  ๋ฐ ๋…ธ์ถœ(CVE) ์ด๋ฆ„, ์‹ค์ œ ์‹ฌ๊ฐ๋„, ๊ณตํ†ต ์ทจ์•ฝ์  ์ ์ˆ˜ ์ฒด๊ณ„ (CVSS) ์ ์ˆ˜, ์ˆ˜์ •์‚ฌํ•ญ (์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ), ์ทจ์•ฝ์ ์ด ํฌํ•จ๋œ ํŒจํ‚ค์ง€์˜ ์ด๋ฆ„, ํŒจํ‚ค์ง€ ์œ ํ˜•์ด ๋‚˜์—ด๋ฉ๋‹ˆ๋‹ค.

      ์ด๋Ÿฌํ•œ ํŒŒ์ผ์„ ํ•„ํ„ฐ๋งํ•˜๊ณ  ์ •๋ ฌํ•˜์—ฌ ํŠน์ • ํŒŒ์ผ, ๋””๋ ‰ํ„ฐ๋ฆฌ ๋˜๋Š” ํŒŒ์ผ ํ™•์žฅ์ž๋ณ„ ํŒŒ์ผ ์œ ํ˜•์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

      Google Cloud ์ฝ˜์†”์—๋Š” ์ด ํ‘œ์— ์ตœ๋Œ€ 1,200๊ฐœ์˜ ์ทจ์•ฝ์ ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€์— ์ทจ์•ฝ์ ์ด 1, 200๊ฐœ๋ฅผ ์ดˆ๊ณผํ•˜๋Š” ๊ฒฝ์šฐ gcloud ๋˜๋Š” API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ „์ฒด ๋ชฉ๋ก์„ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    5. ํŠน์ • CVE์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ๋ณด๋ ค๋ฉด CVE ์ด๋ฆ„์„ ํด๋ฆญํ•˜์„ธ์š”.

    6. ๋ฒ„์ „ ๋ฒˆํ˜ธ ๋ฐ ์˜ํ–ฅ์„ ๋ฐ›๋Š” ์œ„์น˜์™€ ๊ฐ™์€ ์ทจ์•ฝ์  ๋ฐœ์ƒ ์„ธ๋ถ€์ •๋ณด๋ฅผ ๋ณด๋ ค๋ฉด ์ทจ์•ฝ์  ์ด๋ฆ„์ด ์žˆ๋Š” ํ–‰์—์„œ ๋ณด๊ธฐ ๋˜๋Š” ํ•ด๊ฒฐ๋œ ํ•ญ๋ชฉ ๋ณด๊ธฐ๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค. ์ˆ˜์ •์ด ์ ์šฉ๋˜์ง€ ์•Š์€ ์ทจ์•ฝ์ ์˜ ๊ฒฝ์šฐ ๋งํฌ ํ…์ŠคํŠธ๋Š” ๋ณด๊ธฐ์ด๊ณ  ์ˆ˜์ •์ด ์ ์šฉ๋œ ์ทจ์•ฝ์ ์˜ ๊ฒฝ์šฐ ์ˆ˜์ •๋จ ๋ณด๊ธฐ์ž…๋‹ˆ๋‹ค.

    gcloud๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐœ์ƒ ๋ณด๊ธฐ

    ์ด๋ฏธ์ง€์˜ ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ๋ณด๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

    gcloud CLI์—์„œ ๋‹ค์Œ์„ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

      gcloud artifacts docker images list --show-occurrences \
      LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_ID
    

    ๊ฐ ํ•ญ๋ชฉ์˜ ์˜๋ฏธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    • LOCATION์€ ์ €์žฅ์†Œ์˜ ๋ฆฌ์ „ ๋˜๋Š” ๋ฉ€ํ‹ฐ ๋ฆฌ์ „ ์œ„์น˜์ž…๋‹ˆ๋‹ค.
    • PROJECT_ID๋Š” Google Cloud ํ”„๋กœ์ ํŠธ ID์ž…๋‹ˆ๋‹ค.
    • REPOSITORY๋Š” ์ด๋ฏธ์ง€๊ฐ€ ์ €์žฅ๋œ ์ €์žฅ์†Œ์˜ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
    • IMAGE_ID๋Š” ์ €์žฅ์†Œ์˜ ์ด๋ฏธ์ง€ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค. ์ด ๋ช…๋ น์–ด๋กœ ์ด๋ฏธ์ง€ ํƒœ๊ทธ๋ฅผ ์ง€์ •ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

      ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด ๋ช…๋ น์–ด๋Š” ์ตœ์‹  ์ด๋ฏธ์ง€ 10๊ฐœ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ˆ˜์˜ ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋ ค๋ฉด --show-occurrences-from ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ ๋ช…๋ น์–ด๋Š” ๊ฐ€์žฅ ์ตœ๊ทผ ์ด๋ฏธ์ง€ 25๊ฐœ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

      gcloud artifacts docker images list --show-occurrences-from=25 \
      us-central1-docker.pkg.dev/my-project/my-repo/my-image
      

    ์ด๋ฏธ์ง€ ํƒœ๊ทธ ๋˜๋Š” ๋ ˆ์ด์–ด์˜ ์ทจ์•ฝ์ ์„ ๋ณด๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

    gcloud CLI์—์„œ ๋‹ค์Œ์„ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

      gcloud artifacts docker images describe \
      LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_ID:TAG \
      --show-package-vulnerability
    

    ๋˜๋Š”

      gcloud artifacts docker images describe \
      LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_ID@sha256:HASH \
      --show-package-vulnerability
    

    ๊ฐ ํ•ญ๋ชฉ์˜ ์˜๋ฏธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    • LOCATION์€ ์ €์žฅ์†Œ์˜ ๋ฆฌ์ „ ๋˜๋Š” ๋ฉ€ํ‹ฐ ๋ฆฌ์ „ ์œ„์น˜์ž…๋‹ˆ๋‹ค.
    • PROJECT_ID๋Š” Google Cloud ํ”„๋กœ์ ํŠธ ID์ž…๋‹ˆ๋‹ค.
    • REPOSITORY๋Š” ์ด๋ฏธ์ง€๊ฐ€ ์ €์žฅ๋œ ์ €์žฅ์†Œ์˜ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
    • IMAGE_ID๋Š” ์ €์žฅ์†Œ์˜ ์ด๋ฏธ์ง€ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
    • TAG๋Š” ์ •๋ณด๋ฅผ ์–ป์„ ์ด๋ฏธ์ง€ ํƒœ๊ทธ์ž…๋‹ˆ๋‹ค.
    • HASH์€ ์ด๋ฏธ์ง€ ๋‹ค์ด์ œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค.

    ์ทจ์•ฝ์  ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ํ•„ํ„ฐ๋งํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

    gcloud CLI์—์„œ ๋‹ค์Œ์„ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

      gcloud artifacts docker images list --show-occurrences \
      LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_ID --occurrence-filter=FILTER_EXPRESSION
    

    ๊ฐ ํ•ญ๋ชฉ์˜ ์˜๋ฏธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    • LOCATION์€ ์ €์žฅ์†Œ์˜ ๋ฆฌ์ „ ๋˜๋Š” ๋ฉ€ํ‹ฐ ๋ฆฌ์ „ ์œ„์น˜์ž…๋‹ˆ๋‹ค.
    • PROJECT_ID๋Š” Google Cloud ํ”„๋กœ์ ํŠธ ID์ž…๋‹ˆ๋‹ค.
    • REPOSITORY๋Š” ์ด๋ฏธ์ง€๊ฐ€ ์ €์žฅ๋œ ์ €์žฅ์†Œ์˜ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
    • IMAGE_ID๋Š” ์ €์žฅ์†Œ์˜ ์ด๋ฏธ์ง€ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
    • FILTER_EXPRESSION์€ ์ทจ์•ฝ์  ์–ด์ปค๋Ÿฐ์Šค ํ•„ํ„ฐ๋ง์— ์„ค๋ช…๋œ ํ˜•์‹์˜ ์ƒ˜ํ”Œ ํ•„ํ„ฐ๋ง ํ‘œํ˜„์‹์ž…๋‹ˆ๋‹ค.

    API ๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐœ์ƒ ๋ณด๊ธฐ

    ์ด๋ฏธ์ง€์˜ ๋ฐœ์ƒ์„ ๋ณด๋ ค๋ฉด ์ ์ ˆํ•œ ์ฝ”๋“œ ์ƒ˜ํ”Œ์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

    API

    cURL ์‚ฌ์šฉ

    ํ”„๋กœ์ ํŠธ์—์„œ ์–ด์ปค๋Ÿฐ์Šค ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

     curl -X GET -H "Content-Type: application/json" -H \
        "Authorization: Bearer $(gcloud auth print-access-token)" \
        https://containeranalysis.googleapis.com/v1/projects/PROJECT_ID/occurrences
    

    ํ”„๋กœ์ ํŠธ์˜ ์ทจ์•ฝ์  ์š”์•ฝ์„ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

     curl -X GET -H "Content-Type: application/json" -H \
        "Authorization: Bearer $(gcloud auth print-access-token)" \
        https://containeranalysis.googleapis.com/v1/projects/PROJECT_ID/occurrences:vulnerabilitySummary
    

    ํŠน์ • ์–ด์ปค๋Ÿฐ์Šค์— ๋Œ€ํ•œ ์„ธ๋ถ€์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด ๋‹ค์Œ์„ ์‹คํ–‰ํ•˜์„ธ์š”.

     curl -X GET -H "Content-Type: application/json" -H \
        "Authorization: Bearer $(gcloud auth print-access-token)" \
        https://containeranalysis.googleapis.com/v1/projects/PROJECT_ID/occurrences/OCCURRENCE_ID
    

    ๊ฐ ํ•ญ๋ชฉ์˜ ์˜๋ฏธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    • PROJECT_ID๋Š” Google Cloud ํ”„๋กœ์ ํŠธ ID์ž…๋‹ˆ๋‹ค.
    • OCCURRENCE_ID์€ ์„ธ๋ถ€์ •๋ณด๋ฅผ ๋ณด๋ ค๋Š” ๋ฐœ์ƒ์˜ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.

    Java

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Java API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    import com.google.cloud.devtools.containeranalysis.v1.ContainerAnalysisClient;
    import io.grafeas.v1.GrafeasClient;
    import io.grafeas.v1.Occurrence;
    import io.grafeas.v1.ProjectName;
    import java.io.IOException;
    import java.lang.InterruptedException;
    
    public class OccurrencesForImage {
      // Retrieves all the Occurrences associated with a specified image
      // Here, all Occurrences are simply printed and counted
      public static int getOccurrencesForImage(String resourceUrl, String projectId)
          throws IOException, InterruptedException {
        // String resourceUrl = "https://gcr.io/project/image@sha256:123";
        // String projectId = "my-project-id";
        final String projectName = ProjectName.format(projectId);
        final String filterStr = String.format("resourceUrl=\"%s\"", resourceUrl);
    
        // Initialize client that will be used to send requests. After completing all of your requests, 
        // call the "close" method on the client to safely clean up any remaining background resources.
        GrafeasClient client = ContainerAnalysisClient.create().getGrafeasClient();
        int i = 0;
        for (Occurrence o : client.listOccurrences(projectName, filterStr).iterateAll()) {
          // Write custom code to process each Occurrence here
          System.out.println(o.getName());
          i = i + 1;
        }
        return i;
      }
    }

    Go

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Go API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    
    import (
    	"context"
    	"fmt"
    	"io"
    
    	containeranalysis "cloud.google.com/go/containeranalysis/apiv1"
    	"google.golang.org/api/iterator"
    	grafeaspb "google.golang.org/genproto/googleapis/grafeas/v1"
    )
    
    // getOccurrencesForImage retrieves all the Occurrences associated with a specified image.
    // Here, all Occurrences are simply printed and counted.
    func getOccurrencesForImage(w io.Writer, resourceURL, projectID string) (int, error) {
    	// Use this style of URL when you use Google Container Registry.
    	// resourceURL := "https://gcr.io/my-project/my-repo/my-image"
    	// Use this style of URL when you use Google Artifact Registry.
    	// resourceURL := "https://LOCATION-docker.pkg.dev/my-project/my-repo/my-image"
    	ctx := context.Background()
    	client, err := containeranalysis.NewClient(ctx)
    	if err != nil {
    		return -1, fmt.Errorf("NewClient: %w", err)
    	}
    	defer client.Close()
    
    	req := &grafeaspb.ListOccurrencesRequest{
    		Parent: fmt.Sprintf("projects/%s", projectID),
    		Filter: fmt.Sprintf("resourceUrl=%q", resourceURL),
    	}
    	it := client.GetGrafeasClient().ListOccurrences(ctx, req)
    	count := 0
    	for {
    		occ, err := it.Next()
    		if err == iterator.Done {
    			break
    		}
    		if err != nil {
    			return -1, fmt.Errorf("occurrence iteration error: %w", err)
    		}
    		// Write custom code to process each Occurrence here.
    		fmt.Fprintln(w, occ)
    		count = count + 1
    	}
    	return count, nil
    }
    

    Node.js

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Node.js API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    /**
     * TODO(developer): Uncomment these variables before running the sample
     */
    // const projectId = 'your-project-id', // Your GCP Project ID
    // If you are using Google Container Registry
    // const imageUrl = 'https://gcr.io/my-project/my-repo/my-image@sha256:123' // Image to attach metadata to
    // If you are using Google Artifact Registry
    // const imageUrl = 'https://LOCATION-docker.pkg.dev/my-project/my-repo/my-image@sha256:123' // Image to attach metadata to
    
    // Import the library and create a client
    const {ContainerAnalysisClient} = require('@google-cloud/containeranalysis');
    const client = new ContainerAnalysisClient();
    
    const formattedParent = client.getGrafeasClient().projectPath(projectId);
    
    // Retrieves all the Occurrences associated with a specified image
    const [occurrences] = await client.getGrafeasClient().listOccurrences({
      parent: formattedParent,
      filter: `resourceUrl = "${imageUrl}"`,
    });
    
    if (occurrences.length) {
      console.log(`Occurrences for ${imageUrl}`);
      occurrences.forEach(occurrence => {
        console.log(`${occurrence.name}:`);
      });
    } else {
      console.log('No occurrences found.');
    }

    Ruby

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Ruby API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    # resource_url = "The URL of the resource associated with the occurrence."
    #                # e.g. https://gcr.io/project/image@sha256:123"
    # project_id   = "The Google Cloud project ID of the occurrences to retrieve"
    
    require "google/cloud/container_analysis"
    
    # Initialize the client
    client = Google::Cloud::ContainerAnalysis.container_analysis.grafeas_client
    
    parent = client.project_path project: project_id
    filter = "resourceUrl = \"#{resource_url}\""
    count = 0
    client.list_occurrences(parent: parent, filter: filter).each do |occurrence|
      # Process occurrence here
      puts occurrence
      count += 1
    end
    puts "Found #{count} occurrences"

    Python

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Python API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    from google.cloud.devtools import containeranalysis_v1
    
    
    def get_occurrences_for_image(resource_url: str, project_id: str) -> int:
        """Retrieves all the occurrences associated with a specified image.
        Here, all occurrences are simply printed and counted."""
        # resource_url = 'https://gcr.io/my-project/my-image@sha256:123'
        # project_id = 'my-gcp-project'
    
        filter_str = f'resourceUrl="{resource_url}"'
        client = containeranalysis_v1.ContainerAnalysisClient()
        grafeas_client = client.get_grafeas_client()
        project_name = f"projects/{project_id}"
    
        response = grafeas_client.list_occurrences(parent=project_name, filter=filter_str)
        count = 0
        for o in response:
            # do something with the retrieved occurrence
            # in this sample, we will simply count each one
            count += 1
        return count
    
    

    Cloud Build์—์„œ ๋ฐœ์ƒ ๋ณด๊ธฐ

    Cloud Build๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ Google Cloud ์ฝ˜์†”์˜ ๋ณด์•ˆ ํ†ต๊ณ„ ์ธก๋ฉด ํŒจ๋„์—์„œ ์ด๋ฏธ์ง€ ์ทจ์•ฝ์ ์„ ํ™•์ธํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

    ๋ณด์•ˆ ํ†ต๊ณ„ ์ธก๋ฉด ํŒจ๋„์—์„œ๋Š” Artifact Registry์— ์ €์žฅ๋œ ์•„ํ‹ฐํŒฉํŠธ์˜ ๋นŒ๋“œ ๋ณด์•ˆ ์ •๋ณด๋ฅผ ๋Œ€๋žต์ ์œผ๋กœ ๊ฐœ์š”๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ธก๋ฉด ํŒจ๋„๊ณผ Cloud Build๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์†Œํ”„ํŠธ์›จ์–ด ๊ณต๊ธ‰๋ง์„ ๋ณดํ˜ธํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ž์„ธํžˆ ์•Œ์•„๋ณด๋ ค๋ฉด ๋นŒ๋“œ ๋ณด์•ˆ ํ†ต๊ณ„ ๋ณด๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    ์–ด์ปค๋Ÿฐ์Šค ํ•„ํ„ฐ๋ง

    ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ๋ณด๊ธฐ ์ „์— gcloud ๋ช…๋ น์–ด์˜ ํ•„ํ„ฐ ๋ฌธ์ž์—ด๊ณผ Artifact Analysis API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ํ•„ํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์ง€์›๋˜๋Š” ๊ฒ€์ƒ‰ ํ•„ํ„ฐ๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

    ๋ฐœ๊ฒฌ ์–ด์ปค๋Ÿฐ์Šค ๋ณด๊ธฐ

    ์ด๋ฏธ์ง€๋ฅผ Artifact Registry์— ์ฒ˜์Œ์œผ๋กœ ํ‘ธ์‹œํ•˜๋ฉด Artifact Analysis๊ฐ€ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€์˜ ์ดˆ๊ธฐ ์Šค์บ”์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ํฌํ•จ๋œ ๊ฒ€์ƒ‰ ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

    ์ด๋ฏธ์ง€์˜ ํƒ์ƒ‰ ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ ค๋ฉด ๋‹ค์Œ ํ•„ํ„ฐ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

    kind="DISCOVERY" AND resourceUrl="RESOURCE_URL"

    gcloud

    ์ด๋ฏธ์ง€์˜ ํƒ์ƒ‰ ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

    ์ด ๊ฒฝ์šฐ ๋ช…๋ น์–ด์— ํ‘œํ˜„์‹์ด ์ง์ ‘ ์‚ฌ์šฉ๋˜์ง€๋Š” ์•Š์ง€๋งŒ ๋™์ผํ•œ ์ •๋ณด๊ฐ€ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

    gcloud artifacts docker images list --show-occurrences \
    --occurrence-filter='kind="DISCOVERY"' --format=json \
    LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_ID
    

    ๊ฐ ํ•ญ๋ชฉ์˜ ์˜๋ฏธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    • LOCATION์€ ์ €์žฅ์†Œ์˜ ๋ฆฌ์ „ ๋˜๋Š” ๋ฉ€ํ‹ฐ ๋ฆฌ์ „ ์œ„์น˜์ž…๋‹ˆ๋‹ค.
    • REPOSITORY์€ ์ €์žฅ์†Œ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
    • PROJECT_ID๋Š” Google Cloud ํ”„๋กœ์ ํŠธ ID์ž…๋‹ˆ๋‹ค.
    • IMAGE_ID์€ ๋ณด๋ ค๋Š” ๋ฐœ์ƒ์ด ํฌํ•จ๋œ ์ด๋ฏธ์ง€์˜ ID์ž…๋‹ˆ๋‹ค.

    API

    ํƒ์ƒ‰ ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ ค๋ฉด ํ•„ํ„ฐ ํ‘œํ˜„์‹์„ ์•„๋ž˜์ฒ˜๋Ÿผ URL๋กœ ์ธ์ฝ”๋”ฉํ•˜๊ณ  GET ์š”์ฒญ์— ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    GET https://containeranalysis.googleapis.com/v1/projects/PROJECT_ID/occurrences?filter=kind%3D%22DISCOVERY%22%20AND%20resourceUrl%3D%22ENCODED_RESOURCE_URL%22

    ์ž์„ธํ•œ ๋‚ด์šฉ์€ projects.occurrences.get API ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

    Java

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Java API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    import com.google.cloud.devtools.containeranalysis.v1.ContainerAnalysisClient;
    import io.grafeas.v1.GrafeasClient;
    import io.grafeas.v1.Occurrence;
    import io.grafeas.v1.ProjectName;
    import java.io.IOException;
    import java.lang.InterruptedException;
    
    public class GetDiscoveryInfo {
      // Retrieves and prints the Discovery Occurrence created for a specified image
      // The Discovery Occurrence contains information about the initial scan on the image
      public static void getDiscoveryInfo(String resourceUrl, String projectId) 
          throws IOException, InterruptedException {
        // String resourceUrl = "https://gcr.io/project/image@sha256:123";
        // String projectId = "my-project-id";
        String filterStr = "kind=\"DISCOVERY\" AND resourceUrl=\"" + resourceUrl + "\"";
        final String projectName = ProjectName.format(projectId);
    
        // Initialize client that will be used to send requests. After completing all of your requests, 
        // call the "close" method on the client to safely clean up any remaining background resources.
        GrafeasClient client = ContainerAnalysisClient.create().getGrafeasClient();
        for (Occurrence o : client.listOccurrences(projectName, filterStr).iterateAll()) {
          System.out.println(o);
        }
      }
    }

    Go

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Go API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    
    import (
    	"context"
    	"fmt"
    	"io"
    
    	containeranalysis "cloud.google.com/go/containeranalysis/apiv1"
    	"google.golang.org/api/iterator"
    	grafeaspb "google.golang.org/genproto/googleapis/grafeas/v1"
    )
    
    // getDiscoveryInfo retrieves and prints the Discovery Occurrence created for a specified image.
    // The Discovery Occurrence contains information about the initial scan on the image.
    func getDiscoveryInfo(w io.Writer, resourceURL, projectID string) error {
    	// Use this style of URL when you use Google Container Registry.
    	// resourceURL := "https://gcr.io/my-project/my-repo/my-image"
    	// Use this style of URL when you use Google Artifact Registry.
    	// resourceURL := "https://LOCATION-docker.pkg.dev/my-project/my-repo/my-image"
    	ctx := context.Background()
    	client, err := containeranalysis.NewClient(ctx)
    	if err != nil {
    		return fmt.Errorf("NewClient: %w", err)
    	}
    	defer client.Close()
    
    	req := &grafeaspb.ListOccurrencesRequest{
    		Parent: fmt.Sprintf("projects/%s", projectID),
    		Filter: fmt.Sprintf(`kind="DISCOVERY" AND resourceUrl=%q`, resourceURL),
    	}
    	it := client.GetGrafeasClient().ListOccurrences(ctx, req)
    	for {
    		occ, err := it.Next()
    		if err == iterator.Done {
    			break
    		}
    		if err != nil {
    			return fmt.Errorf("occurrence iteration error: %w", err)
    		}
    		fmt.Fprintln(w, occ)
    	}
    	return nil
    }
    

    Node.js

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Node.js API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    /**
     * TODO(developer): Uncomment these variables before running the sample
     */
    // const projectId = 'your-project-id', // Your GCP Project ID
    // If you are using Google Container Registry
    // const imageUrl = 'https://gcr.io/my-project/my-repo/my-image:123' // Image to attach metadata to
    // If you are using Google Artifact Registry
    // const imageUrl = 'https://LOCATION-docker.pkg.dev/my-project/my-repo/my-image:123' // Image to attach metadata to
    
    // Import the library and create a client
    const {ContainerAnalysisClient} = require('@google-cloud/containeranalysis');
    const client = new ContainerAnalysisClient();
    
    const formattedParent = client.getGrafeasClient().projectPath(projectId);
    // Retrieves and prints the Discovery Occurrence created for a specified image
    // The Discovery Occurrence contains information about the initial scan on the image
    const [occurrences] = await client.getGrafeasClient().listOccurrences({
      parent: formattedParent,
      filter: `kind = "DISCOVERY" AND resourceUrl = "${imageUrl}"`,
    });
    
    if (occurrences.length > 0) {
      console.log(`Discovery Occurrences for ${imageUrl}`);
      occurrences.forEach(occurrence => {
        console.log(`${occurrence.name}:`);
      });
    } else {
      console.log('No occurrences found.');
    }

    Ruby

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Ruby API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    # resource_url = "The URL of the resource associated with the occurrence."
    #                # e.g. https://gcr.io/project/image@sha256:123
    # project_id   = "The Google Cloud project ID of the occurrences to retrieve"
    
    require "google/cloud/container_analysis"
    
    # Initialize the client
    client = Google::Cloud::ContainerAnalysis.container_analysis.grafeas_client
    
    parent = client.project_path project: project_id
    filter = "kind = \"DISCOVERY\" AND resourceUrl = \"#{resource_url}\""
    client.list_occurrences(parent: parent, filter: filter).each do |occurrence|
      # Process discovery occurrence here
      puts occurrence
    end

    Python

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Python API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    from google.cloud.devtools import containeranalysis_v1
    
    
    def get_discovery_info(resource_url: str, project_id: str) -> None:
        """Retrieves and prints the discovery occurrence created for a specified
        image. The discovery occurrence contains information about the initial
        scan on the image."""
        # resource_url = 'https://gcr.io/my-project/my-image@sha256:123'
        # project_id = 'my-gcp-project'
    
        filter_str = f'kind="DISCOVERY" AND resourceUrl="{resource_url}"'
        client = containeranalysis_v1.ContainerAnalysisClient()
        grafeas_client = client.get_grafeas_client()
        project_name = f"projects/{project_id}"
        response = grafeas_client.list_occurrences(parent=project_name, filter_=filter_str)
        for occ in response:
            print(occ)
    
    

    ์ทจ์•ฝ์  ์–ด์ปค๋Ÿฐ์Šค ๋ณด๊ธฐ

    ํŠน์ • ์ด๋ฏธ์ง€์˜ ์ทจ์•ฝ์  ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ๋ณด๋ ค๋ฉด ํ•„ํ„ฐ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

    kind="VULNERABILITY" AND resourceUrl="RESOURCE_URL"

    gcloud

    ์ด๋ฏธ์ง€์˜ ์ทจ์•ฝ์  ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ๋ณด๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

    ์ด ๊ฒฝ์šฐ ๋ช…๋ น์–ด์— ํ‘œํ˜„์‹์ด ์ง์ ‘ ์‚ฌ์šฉ๋˜์ง€๋Š” ์•Š์ง€๋งŒ ๋™์ผํ•œ ์ •๋ณด๊ฐ€ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

    gcloud artifacts docker images list --show-occurrences \
    --occurrence-filter='kind="VULNERABILITY"' --format=json \
    LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_ID
    

    ๊ฐ ํ•ญ๋ชฉ์˜ ์˜๋ฏธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    • LOCATION์€ ์ €์žฅ์†Œ์˜ ๋ฆฌ์ „ ๋˜๋Š” ๋ฉ€ํ‹ฐ ๋ฆฌ์ „ ์œ„์น˜์ž…๋‹ˆ๋‹ค.
    • REPOSITORY์€ ์ €์žฅ์†Œ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
    • PROJECT_ID๋Š” Google Cloud ํ”„๋กœ์ ํŠธ ID์ž…๋‹ˆ๋‹ค.
    • IMAGE_ID์€ ๋ณด๋ ค๋Š” ๋ฐœ์ƒ์ด ํฌํ•จ๋œ ์ด๋ฏธ์ง€์˜ ID์ž…๋‹ˆ๋‹ค.

    API

    ๋ฆฌ์†Œ์Šค URL์€ URL๋กœ ์ธ์ฝ”๋”ฉ๋˜์–ด์•ผ ํ•˜๋ฉฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์ด GET ์š”์ฒญ์— ํฌํ•จ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    GET https://containeranalysis.googleapis.com/v1/projects/PROJECT_ID/occurrences?filter=kind%3D%22VULNERABILITY%22%20AND%20resourceUrl%3D%22ENCODED_RESOURCE_URL%22

    ์ž์„ธํ•œ ๋‚ด์šฉ์€ projects.occurrences.get API ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

    Java

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Java API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    import com.google.cloud.devtools.containeranalysis.v1.ContainerAnalysisClient;
    import io.grafeas.v1.GrafeasClient;
    import io.grafeas.v1.Occurrence;
    import io.grafeas.v1.ProjectName;
    import java.io.IOException;
    import java.util.LinkedList;
    import java.util.List;
    
    public class VulnerabilityOccurrencesForImage {
      // Retrieve a list of vulnerability occurrences assoviated with a resource
      public static List<Occurrence> findVulnerabilityOccurrencesForImage(String resourceUrl, 
          String projectId) throws IOException {
        // String resourceUrl = "https://gcr.io/project/image@sha256:123";
        // String projectId = "my-project-id";
        final String projectName = ProjectName.format(projectId);
        String filterStr = String.format("kind=\"VULNERABILITY\" AND resourceUrl=\"%s\"", resourceUrl);
    
        // Initialize client that will be used to send requests. After completing all of your requests, 
        // call the "close" method on the client to safely clean up any remaining background resources.
        GrafeasClient client = ContainerAnalysisClient.create().getGrafeasClient();
        LinkedList<Occurrence> vulnerabilitylist = new LinkedList<Occurrence>();
        for (Occurrence o : client.listOccurrences(projectName, filterStr).iterateAll()) {
          vulnerabilitylist.add(o);
        }
        return vulnerabilitylist;
      }
    }

    Go

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Go API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    
    import (
    	"context"
    	"fmt"
    
    	containeranalysis "cloud.google.com/go/containeranalysis/apiv1"
    	"google.golang.org/api/iterator"
    	grafeaspb "google.golang.org/genproto/googleapis/grafeas/v1"
    )
    
    // findVulnerabilityOccurrencesForImage retrieves all vulnerability Occurrences associated with a resource.
    func findVulnerabilityOccurrencesForImage(resourceURL, projectID string) ([]*grafeaspb.Occurrence, error) {
    	// Use this style of URL when you use Google Container Registry.
    	// resourceURL := "https://gcr.io/my-project/my-repo/my-image"
    	// Use this style of URL when you use Google Artifact Registry.
    	// resourceURL := "https://LOCATION-docker.pkg.dev/my-project/my-repo/my-image"
    	ctx := context.Background()
    	client, err := containeranalysis.NewClient(ctx)
    	if err != nil {
    		return nil, fmt.Errorf("NewClient: %w", err)
    	}
    	defer client.Close()
    
    	req := &grafeaspb.ListOccurrencesRequest{
    		Parent: fmt.Sprintf("projects/%s", projectID),
    		Filter: fmt.Sprintf("resourceUrl = %q kind = %q", resourceURL, "VULNERABILITY"),
    	}
    
    	var occurrenceList []*grafeaspb.Occurrence
    	it := client.GetGrafeasClient().ListOccurrences(ctx, req)
    	for {
    		occ, err := it.Next()
    		if err == iterator.Done {
    			break
    		}
    		if err != nil {
    			return nil, fmt.Errorf("occurrence iteration error: %w", err)
    		}
    		occurrenceList = append(occurrenceList, occ)
    	}
    
    	return occurrenceList, nil
    }
    

    Node.js

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Node.js API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    /**
     * TODO(developer): Uncomment these variables before running the sample
     */
    // const projectId = 'your-project-id', // Your GCP Project ID
    // If you are using Google Container Registry
    // const imageUrl = 'https://gcr.io/my-project/my-repo/my-image:123' // Image to attach metadata to
    // If you are using Google Artifact Registry
    // const imageUrl = 'https://LOCATION-docker.pkg.dev/my-project/my-repo/my-image:123' // Image to attach metadata to
    
    // Import the library and create a client
    const {ContainerAnalysisClient} = require('@google-cloud/containeranalysis');
    const client = new ContainerAnalysisClient();
    
    const formattedParent = client.getGrafeasClient().projectPath(projectId);
    
    // Retrieve a list of vulnerability occurrences assoviated with a resource
    const [occurrences] = await client.getGrafeasClient().listOccurrences({
      parent: formattedParent,
      filter: `kind = "VULNERABILITY" AND resourceUrl = "${imageUrl}"`,
    });
    
    if (occurrences.length) {
      console.log(`All Vulnerabilities for ${imageUrl}`);
      occurrences.forEach(occurrence => {
        console.log(`${occurrence.name}:`);
      });
    } else {
      console.log('No occurrences found.');
    }

    Ruby

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Ruby API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    # resource_url = "The URL of the resource associated with the occurrence
    #                e.g. https://gcr.io/project/image@sha256:123"
    # project_id   = "The Google Cloud project ID of the vulnerabilities to find"
    
    require "google/cloud/container_analysis"
    
    # Initialize the client
    client = Google::Cloud::ContainerAnalysis.container_analysis.grafeas_client
    
    parent = client.project_path project: project_id
    filter = "resourceUrl = \"#{resource_url}\" AND kind = \"VULNERABILITY\""
    client.list_occurrences parent: parent, filter: filter

    Python

    Artifact Analysis์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Artifact Analysis ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Artifact Analysis Python API ์ฐธ๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

    Artifact Analysis์— ์ธ์ฆํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์˜ ์ธ์ฆ ์„ค์ •์„ ์ฐธ์กฐํ•˜์„ธ์š”.

    from typing import List
    
    from google.cloud.devtools import containeranalysis_v1
    from grafeas.grafeas_v1 import types
    
    
    def find_vulnerabilities_for_image(
        resource_url: str, project_id: str
    ) -> List[types.grafeas.Occurrence]:
        """ "Retrieves all vulnerability occurrences associated with a resource."""
        # resource_url = 'https://gcr.io/my-project/my-image@sha256:123'
        # project_id = 'my-gcp-project'
    
        client = containeranalysis_v1.ContainerAnalysisClient()
        grafeas_client = client.get_grafeas_client()
        project_name = f"projects/{project_id}"
    
        filter_str = 'kind="VULNERABILITY" AND resourceUrl="{}"'.format(resource_url)
        return list(grafeas_client.list_occurrences(parent=project_name, filter=filter_str))
    
    

    ํŠน์ • ์œ ํ˜•์˜ ์–ด์ปค๋Ÿฐ์Šค ๋ณด๊ธฐ

    ์•ž์˜ ๋‘ ์˜ˆ์‹œ์— ๋‚˜์˜จ ํ•„ํ„ฐ ํ‘œํ˜„์‹์˜ ์œ ์ผํ•œ ์ฐจ์ด์ ์€ ์–ด์ปค๋Ÿฐ์Šค ์œ ํ˜•์„ ์‹๋ณ„ํ•˜๋Š” kind ๊ฐ’์ž…๋‹ˆ๋‹ค. ์ด ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ทจ์•ฝ์  ๋˜๋Š” ๋ฐฐํฌ์™€ ๊ฐ™์€ ํŠน์ • ์œ ํ˜•์˜ ์–ด์ปค๋Ÿฐ์Šค๋กœ ๋ชฉ๋ก์„ ์ œํ•œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ํŠน์ • ์ด๋ฏธ์ง€์˜ ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ ค๋ฉด ๋‹ค์Œ ํ•„ํ„ฐ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

    kind="NOTE_KIND" AND resourceUrl="RESOURCE_URL"

    ๊ฐ ํ•ญ๋ชฉ์˜ ์˜๋ฏธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    • NOTE_KIND๋Š” ๋ฉ”๋ชจ์˜ ์ข…๋ฅ˜์ž…๋‹ˆ๋‹ค.
      • ์˜ˆ๋ฅผ ๋“ค์–ด ํƒ์ƒ‰ ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ๋‚˜์—ดํ•˜๋ ค๋ฉด DISCOVERY ์ข…๋ฅ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Artifact Analysis๋Š” ์ด๋ฏธ์ง€๋ฅผ ์ฒ˜์Œ Artifact Registry๋กœ ํ‘ธ์‹œํ•  ๋•Œ ์ด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
      • ์ทจ์•ฝ์  ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ๋‚˜์—ดํ•˜๋ ค๋ฉด VULNERABILITY ์ข…๋ฅ˜๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
    • RESOURCE_URL์€ https://HOSTNAME/PROJECT_ID/IMAGE_ID@sha256:HASH ์ด๋ฏธ์ง€์˜ ์ „์ฒด URL์ž…๋‹ˆ๋‹ค.

    ๋‹ค์Œ ํ•„ํ„ฐ ํ‘œํ˜„์‹์€ ์—ฌ๋Ÿฌ ์ด๋ฏธ์ง€์—์„œ ํŠน์ • ์ข…๋ฅ˜์˜ ์–ด์ปค๋Ÿฐ์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.

    kind="NOTE_KIND" AND has_prefix(resourceUrl, "RESOURCE_URL_PREFIX")

    ๊ฐ ํ•ญ๋ชฉ์˜ ์˜๋ฏธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    • RESOURCE_URL_PREFIX๋Š” ์ผ๋ถ€ ์ด๋ฏธ์ง€์˜ URL ํ”„๋ฆฌํ”ฝ์Šค์ž…๋‹ˆ๋‹ค.
      • ์ด๋ฏธ์ง€์˜ ๋ชจ๋“  ๋ฒ„์ „์„ ๋‚˜์—ดํ•˜๋ ค๋ฉด https://HOSTNAME/PROJECT_ID/IMAGE_ID@๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
      • ํ”„๋กœ์ ํŠธ์˜ ๋ชจ๋“  ์ด๋ฏธ์ง€๋ฅผ ๋‚˜์—ดํ•˜๋ ค๋ฉด https://HOSTNAME/PROJECT_ID/์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

    ํŠน์ • ๋ฉ”๋ชจ์™€ ์—ฐ๊ฒฐ๋œ ์ด๋ฏธ์ง€ ๋ณด๊ธฐ

    ํŠน์ • ๋ฉ”๋ชจ ID์™€ ์—ฐ๊ฒฐ๋œ ๋ฆฌ์†Œ์Šค ๋ชฉ๋ก์„ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํŠน์ • CVE ์ทจ์•ฝ์ ์ด ์žˆ๋Š” ์ด๋ฏธ์ง€๋ฅผ ๋‚˜์—ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ํ”„๋กœ์ ํŠธ์—์„œ ํŠน์ • ๋ฉ”๋ชจ์™€ ์—ฐ๊ฒฐ๋œ ๋ชจ๋“  ์ด๋ฏธ์ง€๋ฅผ ๋‚˜์—ดํ•˜๋ ค๋ฉด ๋‹ค์Œ ํ•„ํ„ฐ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

    noteProjectId="PROVIDER_PROJECT_ID" AND noteId="NOTE_ID"

    ํŠน์ • ๋ฉ”๋ชจ์˜ ํŠน์ • ์ด๋ฏธ์ง€๋ฅผ ํ™•์ธํ•˜๋ ค๋ฉด ๋‹ค์Œ ํ•„ํ„ฐ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

    resourceUrl="RESOURCE_URL" AND noteProjectId="PROVIDER_PROJECT_ID" \
        AND noteId="NOTE_ID"

    ๊ฐ ํ•ญ๋ชฉ์˜ ์˜๋ฏธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    • PROVIDER_PROJECT_ID๋Š” ์ œ๊ณต์—…์ฒด ํ”„๋กœ์ ํŠธ์˜ ID์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด goog-vulnz๋Š” ๊ธฐ๋ณธ ์ทจ์•ฝ์  ๋ถ„์„์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
    • NOTE_ID๋Š” ๋ฉ”๋ชจ์˜ ID์ž…๋‹ˆ๋‹ค. ๋ณด์•ˆ ๊ด€๋ จ ๋ฉ”๋ชจ๋Š” ๋Œ€๊ฐœ CVE-2019-12345 ํ˜•์‹์ž…๋‹ˆ๋‹ค.
    • RESOURCE_URL์€ https://HOSTNAME/PROJECT_ID/IMAGE_ID@sha256:HASH ์ด๋ฏธ์ง€์˜ ์ „์ฒด URL์ž…๋‹ˆ๋‹ค.

    ์˜ˆ๋ฅผ ๋“ค์–ด Google์—์„œ ๋ถ„์„ํ•œ ๋Œ€๋กœ CVE-2017-16231์˜ ์–ด์ปค๋Ÿฐ์Šค๊ฐ€ ์žˆ๋Š” ๋ชจ๋“  ์ด๋ฏธ์ง€๋ฅผ ํ™•์ธํ•˜๋ ค๋ฉด ๋‹ค์Œ ํ•„ํ„ฐ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

    noteProjectId="goog-vulnz" AND noteId="CVE-2017-16231"

    ๋‹ค์Œ ๋‹จ๊ณ„

    • Pub/Sub ์•Œ๋ฆผ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ทจ์•ฝ์  ๋ฐ ๊ธฐํƒ€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์— ๊ด€ํ•œ ์•Œ๋ฆผ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.

    • Artifact Analysis๋ฅผ Binary Authorization๊ณผ ํ†ตํ•ฉํ•˜์—ฌ ์ฆ๋ช…์„ ๋งŒ๋“ค์–ด ์•Œ๋ ค์ง„ ๋ณด์•ˆ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๊ฐ€ ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.