İkili Program Yetkilendirmesi ile GKE Dağıtımlarınızın Güvenliğini Sağlama

Google Kubernetes Engine ve temelindeki kapsayıcı modeli, Bulutta barındırılan uygulamalar için artırılmış ölçeklenebilirlik ve yönetilebilirlik sağlar. Sisteminizin çalışma zamanı ihtiyaçlarına göre esnek yazılım uygulamalarını başlatmak her zamankinden daha kolay.

Ancak bu esneklik yeni zorluklarla birlikte gelebilir. Bu tür ortamlarda, her bileşenin en iyi uygulamalarınıza ve standartlarınıza göre oluşturulmasını, test edilmesini ve piyasaya sürülmesini ve üretim ortamınıza yalnızca yetkili yazılımların dağıtılmasını sağlamak zor olabilir.

İkili Program Yetkilendirmesi (BinAuthz) , Kubernetes Engine kümenize dağıtım zamanı politika uygulaması ekleyerek bu endişelerin bazılarını azaltmayı amaçlayan bir hizmettir. İlkeler, bir veya daha fazla güvenilir tarafın ("onaylayanlar" olarak adlandırılır) bir görüntünün konuşlandırılmadan önce onaylamasını gerektirecek şekilde yazılabilir. Görüntülerin geliştirmeden teste ve üretim kümelerine ilerlediği çok aşamalı bir dağıtım hattı için onaylayıcılar, yazılım bir sonraki aşamaya geçmeden önce gerekli tüm işlemlerin tamamlandığından emin olmak için kullanılabilir.

Onaylayanların kimliği, kriptografik genel anahtarlar kullanılarak oluşturulur ve doğrulanır ve tasdikler, ilgili özel anahtarlar kullanılarak dijital olarak imzalanır. Bu, ortamınızda yazılımın dağıtımına yalnızca güvenilir tarafların yetki vermesini sağlar.

Dağıtım zamanında İkili Program Yetkilendirmesi, kapsayıcı görüntüsünün gerekli tüm kısıtlamaları geçip geçmediğini kontrol ederek tanımladığınız ilkeyi uygular - gerekli tüm onaylayıcıların görüntünün dağıtıma hazır olduğunu doğrulaması da dahil. Görüntü geçerse, hizmet dağıtılmasına izin verir. Aksi takdirde, dağıtım engellenir ve uyumlu olana kadar görüntü dağıtılamaz.

866ef6a5bf86cf5.png

Ne İnşa Edeceksiniz

Bu kod laboratuvarı, İkili Program Yetkilendirmesi kullanılarak bir GKE kümesinin güvenliğinin nasıl sağlanacağını açıklar. Bunu yapmak için, tüm dağıtımların uyması gereken bir politika oluşturacak ve bunu kümeye uygulayacaksınız. İlke oluşturmanın bir parçası olarak, kapsayıcı görüntülerini doğrulayabilen bir tasdik eden oluşturacak ve bunu özel bir görüntüyü imzalayıp çalıştırmak için kullanacaksınız.

Bu codelab'in amacı, kapsayıcı imzalamanın İkili Program Yetkilendirmesi ile nasıl çalıştığına dair kısa bir genel bakış sağlamaktır. Bu bilgiyle, güvenilir tasdik edenler tarafından güvence altına alınan güvenli bir CI / CD ardışık düzeni oluşturma konusunda kendinizi rahat hissetmelisiniz.

Ne Olacaksın rn

  • GKE kümesinde İkili Program Yetkilendirmesi nasıl etkinleştirilir?
  • İkili Program Yetkilendirmesi politikası nasıl tanımlanır?
  • Tasdik eden nasıl oluşturulur ve onu politikayla ilişkilendirilir
  • Tasdik eden olarak bir görüntü nasıl imzalanır

Neye İhtiyacınız Var

İkili Program Yetkilendirmesi, altyapınızın güvenliğiyle ilgili olduğundan, genellikle farklı sorumluluklara sahip birden çok kişi tarafından etkileşimde bulunacaktır. Bu kod laboratuarında, hepsi gibi davranacaksınız. Başlamadan önce, üstleneceğiniz farklı rolleri açıklamak önemlidir:

4426da76922fea23.png Dağıtıcı :

  • Bu kişi / süreç, küme üzerinde kod çalıştırmaktan sorumludur.
  • Özellikle güvenlik garantilerinin nasıl uygulandığıyla ilgilenmezler, bu başka birinin işi.
  • Bir Yazılım Mühendisi veya otomatik bir ardışık düzen olabilir.

5b1748abb8d8b699.png Politika Oluşturucu:

  • Bu kişi, kuruluşun büyük resim güvenlik politikalarından sorumludur.
  • Görevleri, bir kapsayıcı çalıştırılmadan önce geçilmesi gereken kuralların bir kontrol listesini yapmaktır.
  • Güvenli olarak kabul edilebilmesi için bir görüntüyü kimin imzalaması gerektiği de dahil olmak üzere güven zincirinden sorumludurlar.
  • Kurallara nasıl uyulacağına dair teknik ayrıntılarla ilgilenmeleri gerekmez. Bir kaptaki yazılımın ne yaptığını bile bilmeyebilirler. Güven kurulmadan önce ne yapılması gerektiğini bilirler.

dca98cc118cd9139.png Tasdik eden

  • Bu kişi / süreç, sistemin güven zincirindeki bir bağlantıdan sorumludur.
  • Bir kriptografik anahtar tutuyorlar ve onay süreçlerini geçerse bir görüntüyü imzalıyorlar.
  • Politika Oluşturucu, politikayı yüksek düzeyde, soyut bir şekilde belirlerken, Tasdik Eden, politikanın bazı yönlerini somut bir şekilde uygulamaktan sorumludur.
  • Kalite Güvencesi testçisi veya yönetici gibi gerçek bir kişi veya bir CI sisteminde bot olabilir.
  • Sistemin güvenliği güvenilirliğine bağlıdır, bu nedenle özel anahtarlarının güvende tutulması önemlidir.

Bu rollerin her biri, kuruluşunuzdaki tek bir kişiyi veya bir ekipleri temsil edebilir. Bir üretim ortamında, bu roller büyük olasılıkla ayrı Google Cloud Platform (GCP) projeleri tarafından yönetilecek ve kaynaklara erişim, Cloud IAM kullanılarak sınırlı bir şekilde aralarında paylaşılacaktır.

a37eb2ed54b9c2eb.png

Bir Dağıtıcı olarak:

Ortamı Kurmak

Bu kod laboratuvarı, Google Cloud Shell kullanılarak web tarayıcınız üzerinden tamamlanabilir. Yeni bir oturum açmak için aşağıdaki bağlantıya tıklayın:

Google Cloud Shell'i açın

Projenizi Ayarlama

İlk adımımız, altında codelab'i çalıştırmak istediğinizGCP projesini ayarlamaktır. Aşağıdaki komutla hesabınızın altında projelerin bir listesini bulabilirsiniz:

gcloud projects list

Hangi projeyi kullanmak istediğinizi bildiğinizde, onu bir ortam değişkenine ayarlayın, böylece onu codelab'in geri kalanı için kullanabilirsiniz:

PROJECT_ID=<YOUR_CHOSEN_PROJECT_ID>
gcloud config set project $PROJECT_ID

Bir Çalışma Dizini Oluşturma

Bu kod laboratuvarı boyunca birkaç yapılandırma dosyası oluşturacaksınız. Aşağıdakilerden yararlanmak için yeni bir dizin oluşturmak isteyebilirsiniz:

mkdir binauthz-codelab ; cd binauthz-codelab

API'leri etkinleştirme

İkili Program Yetkilendirmesini kullanmadan önce, GCP projenizde ilgili API'leri etkinleştirmeniz gerekir:

//enable GKE to create and manage your cluster
gcloud services enable container.googleapis.com
//enable BinAuthz to manage a policy on the cluster
gcloud services enable binaryauthorization.googleapis.com
//enable KMS to manage cryptographic signing keys
gcloud services enable cloudkms.googleapis.com

Alternatif olarak, projeniz için API'leri Google Cloud Platform API Kitaplığı aracılığıyla etkinleştirebilirsiniz.

Bir Küme Oluşturma

Ardından, bir Kubernetes kümesi oluşturacakproje Kubernetes Motoru üzerinden. Aşağıdaki komut, ikili yetkilendirme etkinleştirilmiş us-central1-a bölgesinde "binauthz-codelab" adlı yeni bir küme oluşturacaktır:

gcloud beta container clusters create \
    --enable-binauthz \
    --zone us-central1-a \
    binauthz-codelab

kubectl oluşturulduktan sonra, onu yerel ortamınıza ekleyin, böylece kubectl kullanarak yerel olarak etkileşimde kubectl :

gcloud container clusters get-credentials binauthz-codelab --zone us-central1-a

Bir Kapsül Çalıştırma

Şimdi yeni kümeye bir konteyner ekleyelim. Aşağıdaki komut, kullanabileceğiniz basit bir Dockerfile oluşturacaktır:

cat << EOF > Dockerfile
   FROM alpine
   CMD tail -f /dev/null
EOF

Bu kapsayıcı, "tail -f / dev / null" komutunu çalıştırmaktan başka hiçbir şey yapmayacaktır, bu da sonsuza kadar beklemesine neden olacaktır. Özellikle kullanışlı bir kapsayıcı değildir, ancak kümenizin güvenliğini test etmenize olanak sağlar.

Kapsayıcıyı oluşturun ve Google Container Registry'ye (GCR) aktarın :

#set the GCR path you will use to host the container image
CONTAINER_PATH=us.gcr.io/${PROJECT_ID}/hello-world

#build container
docker build -t $CONTAINER_PATH ./

#push to GCR
gcloud auth configure-docker --quiet
docker push $CONTAINER_PATH

Artık yeni oluşturulan kapsayıcıyı Container Registry web arayüzünde görebilmeniz gerekir.

8d95f439df5fedb2.png

Şimdi, kapsayıcıyı kümenizde çalıştırın:

kubectl create deployment hello-world --image=$CONTAINER_PATH

Her şey yolunda giderse, konteynırınız sessizce çalışmalıdır.

Bunu, çalışan bölmeleri listeleyerek doğrulayabilirsiniz:

kubectl get pods

a1724f9d39373710.png

Politika Oluşturucu olarak:

Politika Ekleme

Artık kodunuzu kuran ve çalıştıran bir kümeniz var. Şimdi, kümeyi bir ilkeyle güvence altına alın.

İlk adım, bir politika dosyası oluşturmaktır:

cat > ./policy.yaml << EOM
    globalPolicyEvaluationMode: ENABLE
    defaultAdmissionRule:
      evaluationMode: ALWAYS_DENY
      enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
EOM

Bu politika nispeten basittir. GlobalPolicyEvaluationMode satırı, bu politikanın Google tarafından tanımlanan küresel politikayı genişlettiğini bildirir. Bu, tüm resmi GKE kapsayıcılarının varsayılan olarak çalışmasına izin verir. Ek olarak, ilke, diğer tüm bölmelerin reddedileceğini belirten bir defaultAdmissionRule bildirir. Kabul kuralı, bu kurala uymayan tüm bölmelerin küme üzerinde çalışmasının engellenmesi gerektiğini belirten bir forceMode satırı içerir.

Daha karmaşık politikaların nasıl oluşturulacağına ilişkin talimatlar için İkili Program Yetkilendirmesi belgelerine bakın .

ce424657bce1501f.png

Şimdi politikayı projenize uygulayabilirsiniz:

gcloud container binauthz policy import policy.yaml

Alternatif olarak, politika Google Cloud Console kullanıcı arayüzünden de ayarlanabilir.

Bir Dağıtıcı olarak:

Politikanın Test Edilmesi

Yeni politikanız, herhangi bir özel kapsayıcı görüntüsünün kümede konuşlandırılmasını engellemelidir. Bölmenizi silerek ve yeniden çalıştırmayı deneyerek bunu doğrulayabilirsiniz:

kubectl delete deployment --all
kubectl delete event --all
kubectl create deployment hello-world --image=$CONTAINER_PATH

Kümede bölmeleri kontrol ederseniz, bu sefer hiçbir bölmenin çalışmadığını fark etmelisiniz:

kubectl get pods

Bölmelerin kaybolduğunu görmek için komutu ikinci kez çalıştırmanız gerekebilir. kubectl kapsülü politikaya göre kontrol etti, kurallara uymadığını gördü ve reddetti.

Reddetmenin kubectl olayı olarak listelendiğini görebilirsiniz:

kubectl get event --template \
  '{{range.items}}{{"\033[0;36m"}}{{.reason}}:{{"\033[0m"}}{{.message}}{{"\n"}}{{end}}'

d57096ad40933ded.png

İkili Program Yetkilendirmesindeki tasdik edenler, Cloud Container Analysis API'nin üzerine uygulanır , bu nedenle ilerlemeden önce bunun nasıl çalıştığını açıklamak önemlidir. Container Analysis API, meta verileri belirli kapsayıcı görüntüleriyle ilişkilendirmenize izin verecek şekilde tasarlanmıştır.

Örnek olarak, Heartbleed güvenlik açığını izlemek için bir Not oluşturulabilir. Güvenlik satıcıları daha sonra güvenlik açığı için kapsayıcı görüntülerini test etmek için tarayıcılar oluşturur ve tehlikeye atılan her bir kapsayıcıyla ilişkili bir Olay oluşturur.

208aa5ebc53ff2b3.png

Güvenlik açıklarını izleme ile birlikte, Container Analysis, genel bir meta veri API'si olacak şekilde tasarlanmıştır. İkili Program Yetkilendirmesi, imzaları doğruladıkları kapsayıcı görüntüleriyle ilişkilendirmek için Kapsayıcı Analizini kullanır **. ** Tek bir onaylayanı temsil etmek için bir Kapsayıcı Analiz Notu kullanılır ve Oluşumlar oluşturulur ve tasdik edenin onayladığı her kapsayıcıyla ilişkilendirilir.

İkili Program Yetkilendirme API'sı, "onaylayanlar" ve "doğrulamalar" kavramlarını kullanır, ancak bunlar, Container Analysis API'deki karşılık gelen Notlar ve Oluşumlar kullanılarak uygulanır.

63a701bd0057ea17.png

Şu anda küme, resmi bir depoda bulunmayan tüm görüntülerde tümünü yakalama reddi gerçekleştirecektir. Bir sonraki adımınız, güvenilir kapsayıcılara seçici olarak izin verebilmeniz için bir tasdik eden oluşturmaktır.

Tasdik Eden olarak:

Bir Konteyner Analiz Notu Oluşturma

36f8f5ade32507f7.png

Notunuz için gerekli verileri içeren bir JSON dosyası oluşturarak başlayın. Bu komut, Notunuzu yerel olarak içeren bir JSON dosyası oluşturacaktır:

cat > ./create_note_request.json << EOM
{
  "attestation": {
    "hint": {
      "human_readable_name": "This note represents an attestation authority"
    }
  }
}
EOM

Şimdi, Kapsayıcı Analizi API'sini kullanarak Notu projenize gönderin:

NOTE_ID=my-attestor-note

curl -vvv -X POST \
    -H "Content-Type: application/json"  \
    -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
    --data-binary @./create_note_request.json  \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/?noteId=${NOTE_ID}"

Notun kaydedildiğini geri getirerek doğrulayabilirsiniz:

curl -vvv  \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}"

İkili Program Yetkilendirmesinde Onaylayan Oluşturma

af0267ab7f7757f9.png

Notunuz artık Container Analysis API içinde kaydedildi. Onaylayıcınızdan yararlanmak için notu İkili Program Yetkilendirmesine de kaydetmeniz gerekir:

ATTESTOR_ID=my-binauthz-attestor

gcloud container binauthz attestors create $ATTESTOR_ID \
    --attestation-authority-note=$NOTE_ID \
    --attestation-authority-note-project=${PROJECT_ID}

Her şeyin beklendiği gibi çalıştığını doğrulamak için kayıtlı yetkililerin listesini yazdırın:

gcloud container binauthz attestors list

9ef5aba66d1b06d3.png

Yeni onaylayıcınızı Google Cloud Console kullanıcı arayüzü aracılığıyla da görebilmelisiniz.

IAM Rolü Ekleniyor

Bu tasdik edeni kullanmadan önce, oluşturduğunuz Kapsayıcı Analiz Notunu görüntülemek için İkili Program Yetkilendirmesine uygun izinleri vermelisiniz. Bu, İkili Program Yetkilendirmesinin, her bir kapsülün imzalandığından ve çalıştırılmak üzere onaylandığından emin olmak için Container Analysis API'yi sorgulamasına olanak tanır.

İkili Program Yetkilendirmesindeki izinler, otomatik olarak oluşturulan bir hizmet hesabı aracılığıyla işlenir.

Önce, hizmet hesabının e-posta adresini bulun:

PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}"  --format="value(projectNumber)")
BINAUTHZ_SA_EMAIL="service-${PROJECT_NUMBER}@gcp-sa-binaryauthorization.iam.gserviceaccount.com"

Şimdi bunu bir Container Analysis IAM JSON isteği oluşturmak için kullanın:

cat > ./iam_request.json << EOM
{
  'resource': 'projects/${PROJECT_ID}/notes/${NOTE_ID}',
  'policy': {
    'bindings': [
      {
        'role': 'roles/containeranalysis.notes.occurrences.viewer',
        'members': [
          'serviceAccount:${BINAUTHZ_SA_EMAIL}'
        ]
      }
    ]
  }
}
EOM

Gerekli IAM rolünü vermek için bir curl isteğinde bulunun:

curl -X POST  \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    --data-binary @./iam_request.json \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}:setIamPolicy"

KMS Anahtarı Ekleme

1e3af7c177f7a311.png

Bu tasdik ediciyi kullanmadan önce, yetkilinizin kapsayıcı görüntülerini imzalamak için kullanılabilecek bir şifreleme anahtarı çifti oluşturması gerekir. Bu, Google Cloud Key Management Service (KMS) aracılığıyla yapılabilir.

İlk olarak, yeni anahtarı açıklamak için bazı ortam değişkenleri ekleyin

KEY_LOCATION=global
KEYRING=binauthz-keys
KEY_NAME=codelab-key
KEY_VERSION=1

Bir dizi anahtarı tutmak için bir anahtarlık oluşturun

gcloud kms keyrings create "${KEYRING}" --location="${KEY_LOCATION}"

Tasdik eden için yeni bir asimetrik imzalama anahtarı çifti oluşturun

gcloud kms keys create "${KEY_NAME}" \
    --keyring="${KEYRING}" --location="${KEY_LOCATION}" \
    --purpose asymmetric-signing  --default-algorithm="ec-sign-p256-sha256"

Anahtarınızın Google Cloud Console'un KMS sayfasında göründüğünü görmelisiniz. Şimdi, gcloud binauthz komutu aracılığıyla anahtarı yetkinizle ilişkilendirin :

gcloud beta container binauthz attestors public-keys add  \
    --attestor="${ATTESTOR_ID}"  \
    --keyversion-project="${PROJECT_ID}"  \
    --keyversion-location="${KEY_LOCATION}" \
    --keyversion-keyring="${KEYRING}" \
    --keyversion-key="${KEY_NAME}" \
    --keyversion="${KEY_VERSION}"

Yetki listesini tekrar yazdırırsanız, şimdi kayıtlı bir anahtar görmelisiniz:

gcloud container binauthz attestors list

c5ad61fbf14f1885.png

Her yetki için birden fazla anahtarın kaydedilebileceğini unutmayın. Yetkili kişi bir ekibi temsil ediyorsa bu yararlı olabilir. Örneğin, QA ekibindeki herhangi biri QA Tasdik Eden olarak hareket edebilir ve kendi özel anahtarıyla imzalayabilir.

Tasdik Eden olarak:

Artık yetkinizi oluşturduğunuza ve kullanıma hazır olduğunuza göre, bunu daha önce oluşturduğunuz konteyner görüntüsünü imzalamak için kullanabilirsiniz.

İmzalı Bir Tasdik Oluşturma

858d7e6feeb6f159.png

Bir tasdik, belirli bir kapsayıcı görüntüsünün tasdik eden tarafından doğrulandığını ve kümenizde çalıştırılmasının güvenli olduğunu belirtmek için bir şifreleme imzası içermelidir. Hangi kap görüntüsünün onaylanacağını belirtmek için özetini belirlemeniz gerekir. Aşağıdakileri çalıştırarak Container Registry'de barındırılan belirli bir kapsayıcı etiketinin özetini bulabilirsiniz:

DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:latest \
    --format='get(image_summary.digest)')

Artık onayınızı oluşturmak için gcloud'u kullanabilirsiniz. Komut, yalnızca imzalamak için kullanmak istediğiniz anahtarın ayrıntılarını ve onaylamak istediğiniz belirli kapsayıcı görüntüsünü alır.

gcloud beta container binauthz attestations sign-and-create  \
    --artifact-url="${CONTAINER_PATH}@${DIGEST}" \
    --attestor="${ATTESTOR_ID}" \
    --attestor-project="${PROJECT_ID}" \
    --keyversion-project="${PROJECT_ID}" \
    --keyversion-location="${KEY_LOCATION}" \
    --keyversion-keyring="${KEYRING}" \
    --keyversion-key="${KEY_NAME}" \
    --keyversion="${KEY_VERSION}"

Kapsayıcı Analizi açısından, bu yeni bir oluşum yaratacak ve bunu tasdik edenin notuna ekleyecektir. Her şeyin beklendiği gibi çalıştığından emin olmak için tasdiklerinizi listeleyebilirsiniz.

gcloud container binauthz attestations list \
   --attestor=$ATTESTOR_ID --attestor-project=${PROJECT_ID}

Artık, bu kapsayıcı görüntüsünü çalıştırmayı denediğinizde İkili Program Yetkilendirmesi, onaylayan tarafından imzalandığını ve doğrulandığını ve çalıştırmanın güvenli olduğunu belirleyebilecek

Artık resminizi bir tasdik eden tarafından güvenli bir şekilde doğruladığınıza göre, onu küme üzerinde çalıştıralım.

Politika Oluşturucu olarak:

Politikanın Güncellenmesi

Şu anda kümeniz tek bir kuralı olan bir ilke yürütüyor: resmi depolardan gelen kapsayıcılara izin verin ve diğerlerini reddedin.

Onaylayan tarafından doğrulanan tüm görüntülere izin vermek için değiştirin:

cat << EOF > updated_policy.yaml
    globalPolicyEvaluationMode: ENABLE
    defaultAdmissionRule:
      evaluationMode: REQUIRE_ATTESTATION
      enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
      requireAttestationsBy:
      - projects/${PROJECT_ID}/attestors/${ATTESTOR_ID}
EOF

Artık diskte updated_policy.yaml adında yeni bir dosyanız olmalıdır. Şimdi, tüm görüntüleri reddeden varsayılan kural yerine, önce onaylayıcınızı doğrulamalar için kontrol eder.

822240fc0b02408e.png

Yeni politikayı İkili Program Yetkilendirmesine yükleyin:

gcloud container binauthz policy import updated_policy.yaml

Bir Dağıtıcı olarak:

Doğrulanmış Resmi Çalıştırma

Ardından, imzalı görüntüyü çalıştıracak ve bölmenin aşağıdaki komutla çalıştığını doğrulayacaksınız:

kubectl create deployment hello-world-signed --image="${CONTAINER_PATH}@${DIGEST}"

Şimdi, bölmenizin çalışıp çalışmadığını kontrol edin:

kubectl get pods

Bölmenizin politikayı geçtiğini ve küme üzerinde çalıştığını görmelisiniz.

Tebrikler! Artık ilkeye daha karmaşık kurallar ekleyerek kümeniz için belirli güvenlik garantileri verebilirsiniz.

Kümeyi silin:

gcloud container clusters delete binauthz-codelab --zone us-central1-a

Kap görüntüsünü silin:

gcloud container images delete $CONTAINER_PATH@$DIGEST --force-delete-tags

Tasdik Eden'i Silin:

gcloud container binauthz attestors delete my-binauthz-attestor

Kapsayıcı Analizi kaynaklarını silin:

curl -vvv -X DELETE  \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}"