Memastikan kompatibilitas sertifikat webhook sebelum mengupgrade ke v1.23


Mulai versi 1.23, Kubernetes tidak lagi mendukung validasi identitas server menggunakan kolom Common Name (CN) X.509 dalam sertifikat. Sebagai gantinya, Kubernetes hanya akan mengandalkan informasi di kolom X.509 Subject Alternative Name (SAN).

Untuk mencegah dampak pada cluster, Anda harus mengganti sertifikat yang tidak kompatibel dan tidak memiliki SAN untuk backend webhook dan server API gabungan sebelum mengupgrade cluster ke Kubernetes versi 1.23.

Alasan Kubernetes tidak lagi mendukung sertifikat backend tanpa SAN

GKE mengoperasikan Kubernetes open source, yang menggunakan komponen kube-apiserver untuk menghubungi webhook dan backend server API gabungan menggunakan Transport Layer Security (TLS). Komponen kube-apiserver ditulis dalam bahasa pemrograman Go.

Sebelum Go 1.15, klien TLS memvalidasi identitas server yang dihubungkan menggunakan proses dua langkah:

  1. Memeriksa apakah nama DNS (atau alamat IP) server ada sebagai salah satu SAN pada sertifikat server.
  2. Jika pemeriksaan tersebut gagal, klien TLS akan memeriksa apakah nama DNS (atau alamat IP) server sama dengan CN pada sertifikat server.

RFC 6125 sepenuhnya menghentikan penggunaan validasi identitas server menggunakan kolom CN pada tahun 2011. Browser dan aplikasi lain yang penting bagi keamanan tidak lagi menggunakan kolom ini.

Agar selaras dengan ekosistem TLS yang lebih luas, Go 1.15 menghapus Langkah 2 dari proses validasinya, tetapi membiarkan tombol debug (x509ignoreCN=0) untuk mengaktifkan perilaku lama guna memudahkan proses migrasi. Kubernetes versi 1.19 adalah versi pertama yang dibangun menggunakan Go 1.15. Cluster GKE pada versi dari 1.19 hingga 1.22 mengaktifkan tombol debug secara default untuk memberi pelanggan lebih banyak waktu guna mengganti sertifikat untuk webhook dan backend server API gabungan yang terpengaruh.

Kubernetes versi 1.23 dibangun dengan Go 1.17, yang menghapus tombol debug. Setelah GKE mengupgrade cluster Anda ke versi 1.23, panggilan dari panel kontrol cluster ke webhook atau layanan API gabungan yang tidak memberikan sertifikat X.509 yang valid dengan SAN yang sesuai akan gagal terhubung.

Mengidentifikasi cluster yang terpengaruh

Untuk cluster yang menjalankan versi patch minimal 1.21.9 atau 1.22.3

Untuk cluster pada versi patch 1.21.9 dan 1.22.3 atau yang lebih baru dengan Cloud Logging diaktifkan, GKE menyediakan log Cloud Audit Logs untuk mengidentifikasi panggilan ke backend yang terpengaruh dari cluster Anda. Anda dapat menggunakan filter berikut untuk menelusuri log:

logName =~ "projects/.*/logs/cloudaudit.googleapis.com%2Factivity"
resource.type = "k8s_cluster"
operation.producer = "k8s.io"
"invalid-cert.webhook.gke.io"

Jika cluster Anda belum memanggil backend dengan sertifikat yang terpengaruh, Anda tidak akan melihat log apa pun. Jika Anda melihat log audit seperti itu, log tersebut akan menyertakan nama host dari backend yang terpengaruh.

Berikut adalah contoh entri log, untuk backend webhook yang dihosting oleh layanan bernama example-webhook di namespace default:

{
  ...
  resource {
    type: "k8s_cluster",
    "labels": {
      "location": "us-central1-c",
      "cluster_name": "example-cluster",
      "project_id": "example-project"
    }
  },
  labels: {
    invalid-cert.webhook.gke.io/example-webhook.default.svc: "No subjectAltNames returned from example-webhook.default.svc:8443",
    ...
  },
  logName: "projects/example-project/logs/cloudaudit.googleapis.com%2Factivity",
  operation: {
    ...
    producer: "k8s.io",
    ...
  },
  ...
}

Nama host layanan yang terpengaruh (misalnya, example-webhook.default.svc) disertakan sebagai akhiran dalam nama label yang diawali dengan invalid-cert.webhook.gke.io/. Anda juga bisa mendapatkan nama cluster yang melakukan panggilan dari label resource.labels.cluster_name, yang memiliki nilai example-cluster dalam contoh ini.

Insight penghentian penggunaan

Anda dapat mengetahui cluster mana yang menggunakan sertifikat yang tidak kompatibel dengan melihat insight penghentian penggunaan. Insight tersedia untuk cluster yang menjalankan versi 1.22.6-gke.1000 atau yang lebih baru.

Versi cluster lainnya

Jika Anda memiliki cluster pada versi patch yang lebih lama dari 1.22.3 pada versi minor 1.22, atau versi patch yang lebih lama dari 1.21.9, Anda memiliki dua opsi untuk menentukan apakah cluster Anda terpengaruh oleh penghentian penggunaan ini:

Opsi 1 (direkomendasikan): Upgrade cluster Anda ke versi patch yang mendukung identifikasi sertifikat yang terpengaruh dengan log. Pastikan Cloud Logging diaktifkan untuk cluster Anda. Setelah cluster Anda diupgrade, log Cloud Audit Logs yang mengidentifikasi akan dihasilkan setiap kali cluster mencoba memanggil Layanan yang tidak menyediakan sertifikat dengan SAN yang sesuai. Karena log hanya akan dibuat pada saat ada upaya panggilan, sebaiknya tunggu selama 30 hari setelah upgrade untuk memberi waktu yang cukup agar semua jalur panggilan dipanggil.

Sebaiknya gunakan log untuk mengidentifikasi layanan yang terpengaruh karena pendekatan ini meminimalkan upaya manual dengan otomatis membuat log guna menampilkan layanan yang terpengaruh.

Opsi 2: Periksa sertifikat yang digunakan oleh Webhook atau Server API Agregat di cluster Anda untuk menentukan apakah sertifikat tersebut terpengaruh karena tidak memiliki SAN:

  1. Dapatkan daftar Webhook dan Server API Agregat di cluster Anda, lalu identifikasi backend-nya (Layanan atau URL).
  2. Periksa sertifikat yang digunakan oleh layanan backend.

Mengingat upaya manual yang diperlukan untuk memeriksa semua sertifikat dengan cara ini, metode ini hanya boleh dilakukan jika Anda perlu menilai dampak penghentian penggunaan di Kubernetes versi 1.23 sebelum mengupgrade cluster ke versi 1.21. Jika dapat mengupgrade cluster ke 1.21, Anda harus mengupgradenya terlebih dahulu, lalu mengikuti petunjuk di Opsi 1 untuk menghindari upaya manual.

Mengidentifikasi layanan backend yang akan diperiksa

Untuk mengidentifikasi backend yang mungkin terpengaruh oleh penghentian penggunaan, dapatkan daftar Webhook dan Layanan API Gabungan serta backend terkaitnya di cluster.

Untuk menampilkan daftar semua webhook yang relevan di cluster, gunakan perintah kubectl berikut:

kubectl get mutatingwebhookconfigurations -A   # mutating admission webhooks

kubectl get validatingwebhookconfigurations -A # validating admission webhooks

Anda bisa mendapatkan Layanan atau URL backend terkait untuk Webhook tertentu dengan memeriksa kolom clientConfig.service atau kolom webhooks.clientConfig.url di konfigurasi Webhook:

kubectl get mutatingwebhookconfigurations example-webhook -o yaml

Output perintah ini akan mirip dengan berikut ini:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
webhooks:
- admissionReviewVersions:
  clientConfig:
    service:
        name: example-service
        namespace: default
        port: 443

Perlu diperhatikan bahwa clientConfig dapat menentukan backend-nya sebagai URL (clientConfig.url), atau sebagai Layanan (clientConfig.service) Kubernetes.

Untuk menampilkan daftar semua Layanan API Gabungan yang relevan di cluster, gunakan perintah kubectl berikut:

kubectl get apiservices -A |grep -v Local      # aggregated API services

Output perintah ini akan mirip dengan berikut ini:

NAME                     SERVICE                      AVAILABLE   AGE
v1beta1.metrics.k8s.io   kube-system/metrics-server   True        237d

Contoh ini menampilkan Layanan metric-server dari namespace kube-system.

Anda bisa mendapatkan Layanan terkait untuk API Gabungan tertentu dengan memeriksa kolom spec.service:

kubectl get apiservices v1beta1.metrics.k8s.io -o yaml

Output perintah ini akan mirip dengan berikut ini:

...
apiVersion: apiregistration.k8s.io/v1
kind: APIService
spec:
  service:
    name: metrics-server
    namespace: kube-system
    port: 443

Memeriksa sertifikat Layanan

Setelah mengidentifikasi Layanan backend yang relevan untuk diperiksa, Anda dapat memeriksa sertifikat setiap Layanan tertentu, seperti example-service:

  1. Temukan pemilih dan port target layanan:

    kubectl describe service example-service
    

    Output perintah ini akan mirip dengan berikut ini:

    Name: example-service
    Namespace: default
    Labels: run=nginx
    Selector: run=nginx
    Type: ClusterIP
    IP: 172.21.xxx.xxx
    Port: 443
    TargetPort: 444
    

    Dalam contoh ini, example-service memiliki pemilih run=nginx dan target port 444.

  2. Temukan pod yang cocok dengan pemilih:

    kubectl get pods --selector=run=nginx
    

    Output perintah ini akan mirip dengan berikut ini:

    NAME          READY   STATUS    RESTARTS   AGE
    example-pod   1/1     Running   0          21m
    
  3. Siapkan penerusan port

    dari localhost kubectl ke pod.

    kubectl port-forward pods/example-pod LOCALHOST_PORT:TARGET_PORT # port forwarding in background
    

    Ganti kode berikut dalam perintah:

    • LOCALHOST_PORT: alamat yang akan diproses.
    • TARGET_PORT TargetPort dari Langkah 1.
  4. Gunakan openssl untuk mencetak sertifikat yang digunakan oleh Layanan:

    openssl s_client -connect localhost:LOCALHOST_PORT </dev/null | openssl x509 -noout -text
    

    Contoh output ini menunjukkan sertifikat yang valid (dengan entri SAN):

    Subject: CN = example-service.default.svc
    X509v3 extensions:
      X509v3 Subject Alternative Name:
        DNS:example-service.default.svc
    

    Contoh output ini menunjukkan sertifikat dengan SAN yang tidak ada:

    Subject: CN = example-service.default.svc
      X509v3 extensions:
          X509v3 Key Usage: critical
              Digital Signature, Key Encipherment
          X509v3 Extended Key Usage:
              TLS Web Server Authentication
          X509v3 Authority Key Identifier:
              keyid:1A:5F:29:D8:E9:3C:54:3C:35:CC:D8:AB:D1:21:FD:C3:56:25:C0:74
    
  5. Hapus penerusan port agar tidak berjalan di latar belakang dengan perintah berikut:

    $ jobs
    [1]+  Running                 kubectl port-forward pods/example-pod 8888:444 &
    $ kill %1
    [1]+  Terminated              kubectl port-forward pods/example 8888:444
    

Memeriksa sertifikat backend URL

Jika webhook menggunakan backend url, langsung hubungkan ke nama host yang ditentukan dalam URL. Misalnya, jika URL-nya adalah https://example.com:123/foo/bar, gunakan perintah openssl berikut untuk mencetak sertifikat yang digunakan oleh backend:

  openssl s_client -connect example.com:123 </dev/null | openssl x509 -noout -text

Memitigasi risiko upgrade 1.23

Setelah mengidentifikasi cluster yang terpengaruh dan layanan backend-nya yang menggunakan sertifikat tanpa SAN, Anda harus memperbarui webhook dan backend server API gabungan agar menggunakan sertifikat dengan SAN yang sesuai sebelum mengupgrade cluster ke versi 1.23.

GKE tidak akan otomatis mengupgrade cluster pada versi 1.22.6-gke.1000 atau yang lebih baru dengan backend yang menggunakan sertifikat yang tidak kompatibel sampai Anda mengganti sertifikat tersebut atau sampai versi 1.22 mencapai akhir dukungan standar.

Jika cluster Anda menggunakan versi GKE yang lebih lama dari 1.22.6-gke.1000, Anda dapat mencegah upgrade otomatis untuk sementara dengan mengonfigurasi pengecualian pemeliharaan guna mencegah upgrade minor.

Resource

Silakan melihat referensi berikut untuk mengetahui informasi tambahan tentang perubahan ini:

  • Catatan rilis Kubernetes 1.23
    • Kubernetes dibangun menggunakan Go 1.17. Versi Go ini menghapus kemampuan untuk menggunakan setelan lingkungan GODEBUG=x509ignoreCN=0. Setelan ini memungkinkan untuk mengaktifkan kembali perilaku lama yang tidak digunakan lagi, yaitu memperlakukan CN X.509 yang menayangkan sertifikat sebagai nama host.
  • Catatan rilis Kubernetes 1.19 dan Kubernetes 1.20
    • Perilaku lama yang tidak digunakan lagi, yaitu memperlakukan kolom CN pada X.509 yang menayangkan sertifikat sebagai nama host jika tidak ada SAN, kini dinonaktifkan secara default.
  • Catatan rilis Go 1.17
    • Flag GODEBUG=x509ignoreCN=0 sementara kini telah dihapus.
  • Catatan rilis Go 1.15
    • Perilaku lama yang tidak digunakan lagi, yaitu memperlakukan kolom CN pada sertifikat X.509 sebagai host jika tidak ada SAN, kini dinonaktifkan secara default.
  • RFC 6125 (halaman 46)
    • Meskipun penggunaan nilai CN adalah praktik yang sudah ada, nilai tersebut tidak digunakan lagi, dan sebagai gantinya Certificate Authority sebaiknya memberikan nilai subjectAltName.
  • Webhook akses