Mari mengenkripsi sertifikat SSL dengan manajer-sertifikat di Kubernetes



Dalam artikel ini saya akan berbicara tentang cara mengotomatisasi pemesanan dan pembaruan sertifikat dari Let's Encrypt (dan tidak hanya) untuk Ingress di Kubernetes menggunakan add-on cert-manager. Tapi saya akan mulai dengan pengantar singkat tentang esensi masalah.

Sedikit program pendidikan


Protokol HTTP, yang dikembangkan pada awal tahun 90-an abad lalu, memasuki kehidupan kita sehari-hari dengan sangat ketat sehingga sulit membayangkan setidaknya sehari tanpa menggunakannya. Namun, dengan sendirinya, itu bahkan tidak memberikan tingkat keamanan minimum ketika bertukar informasi antara pengguna dan server web. HTTPS ("S" - secure) datang untuk menyelamatkan: menggunakan kemasan data yang dikirimkan dalam SSL / TLS, protokol ini telah membuktikan dirinya dalam melindungi informasi dari intersepsi dan secara aktif dipromosikan oleh industri.

Misalnya, Google telah mematuhi 2014Posisi "HTTPS di mana-mana" dan bahkan menurunkan prioritas situs tanpa itu dalam hasil pencarian. "Propaganda" ini tidak memintas konsumen biasa: browser modern memperingatkan pengguna mereka tentang keberadaan dan kebenaran sertifikat SSL untuk situs yang dikunjungi.





Biaya sertifikat untuk situs pribadi dimulai dari puluhan dolar. Tidak selalu membeli itu dibenarkan dan sesuai. Untungnya, sejak akhir 2015, alternatif gratis dalam bentuk sertifikat Let's Encrypt (LE) tersedia . Proyek nirlaba ini dibuat oleh penggemar Mozilla untuk mencakup sebagian besar situs web dengan enkripsi.

Otoritas Sertifikat mengeluarkan sertifikat yang divalidasi domain(yang paling sederhana di antara yang tersedia di pasar) dengan masa berlaku 90 hari, dan selama beberapa tahun sekarang yang disebut sertifikat wildcard untuk beberapa subdomain telah dikeluarkan.

Untuk mendapatkan sertifikat, situs menggunakan algoritma yang dijelaskan dalam protokol Lingkungan Manajemen Sertifikat Otomatis (ACME), yang dibuat khusus untuk Let's Encrypt. Saat menggunakannya, konfirmasi kepemilikan domain dilakukan oleh permintaan melalui penempatan kode HTTP tertentu (disebut HTTP-01 ) atau pemasangan catatan DNS (DNS-01) - lebih lanjut tentang itu akan diberikan di bawah ini.

Manajer sertifikasi


Cert-manager adalah proyek khusus untuk Kubernetes, yang merupakan sekumpulan CustomResourceDefinitions (karenanya pembatasan pada versi K8s yang didukung minimum - v1.12) untuk konfigurasi CA (otoritas sertifikasi) dan pemesanan langsung sertifikat. Menginstal CRD dalam sebuah cluster adalah sepele dan turun menggunakan satu file YAML:

kubectl create ns cert-manager
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v0.13.0/cert-manager.yaml

( Ada juga kemungkinan menginstal menggunakan Helm.)

Untuk memulai prosedur pemesanan, sumber daya dari otoritas sertifikasi (CA) harus dinyatakan dalam kluster: Issueratau ClusterIssuer, - yang digunakan untuk menandatangani CSR (permintaan penerbitan sertifikat). Perbedaan antara sumber daya pertama dan kedua adalah dalam cakupan:

  • Issuer dapat digunakan dalam namespace yang sama,
  • ClusterIssuer adalah objek global cluster.

Berlatih dengan cert-manager


1 Sertifikat yang ditandatangani sendiri


Mari kita mulai dengan kasing paling sederhana - memesan sertifikat yang ditandatangani sendiri. Opsi ini cukup umum, misalnya, untuk lingkungan pengujian dinamis untuk pengembang atau dalam hal menggunakan penyeimbang eksternal yang menghentikan lalu lintas SSL.

Sumber daya Issuerakan terlihat seperti ini:

apiVersion: cert-manager.io/v1alpha2
kind: Issuer
metadata:
  name: selfsigned
spec:
  selfSigned: {}

Dan untuk mengeluarkan sertifikat, perlu untuk menggambarkan sumber Certificate, di mana ditunjukkan bagaimana mengeluarkannya (lihat bagian di issuerRefbawah) dan di mana kunci pribadi (bidang secretName) berada. Setelah itu, Ingress perlu merujuk ke kunci ini (lihat bagian tlsc spec):

---
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: selfsigned-crt
spec:
  secretName: tls-secret
  issuerRef:
    kind: Issuer
    name: selfsigned
  commonName: "yet-another.website"
  dnsNames:
  - "yet-another.website"
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: app
spec:
  tls:
  - hosts:
    - "yet-another.website"
    secretName: tls-secret
  rules:
  - host: "yet-another.website"
    http:
      paths:
      - path: /
        backend:
          serviceName: app
          servicePort: 8080

Beberapa detik setelah menambahkan sumber daya ini ke cluster, sertifikat akan dikeluarkan. Anda dapat melihat laporan terkait di output perintah:

kubectl -n app describe  certificate selfsigned-crt
...
  Normal  GeneratedKey  5s    cert-manager  Generated a new private key
  Normal  Requested     5s    cert-manager  Created new CertificateRequest resource "selfsigned-crt-4198958557"
  Normal  Issued        5s    cert-manager  Certificate issued successfully

Jika Anda melihat sumber rahasia itu sendiri, maka itu berisi:

  • kunci pribadi tls.key,
  • sertifikat root ca.crt,
  • Sertifikat yang ditandatangani sendiri kami tls.crt.

Isi file-file ini dapat dilihat menggunakan utilitas openssl, misalnya, seperti ini:

kubectl -n app get secret tls-secret -ojson | jq -r '.data."tls.crt"' | base64 -d | openssl x509 -dates -noout -issuer
notBefore=Feb 10 21:01:59 2020 GMT
notAfter=May 10 21:01:59 2020 GMT
issuer=O = cert-manager, CN = yet-another.website

Perlu dicatat bahwa dalam kasus umum, sertifikat yang dikeluarkan menggunakan ini tidak akan dipercaya olehIssuer klien yang terhubung . Alasannya sederhana: tidak memiliki CA (lihat catatan di situs web proyek ) . Untuk menghindari ini, Anda perlu menentukan di jalur ke file rahasia di mana file itu terkandung . Ini bisa berupa organisasi CA perusahaan - untuk menandatangani sertifikat yang dikeluarkan untuk Ingress dengan kunci yang sudah digunakan untuk kebutuhan layanan server / sistem informasi lainnya.Certificateca.crt

2 Mari Enkripsi Sertifikat dengan Validasi HTTP


Untuk menerbitkan sertifikat LE, seperti yang disebutkan sebelumnya, ada dua jenis konfirmasi kepemilikan domain yang tersedia : HTTP-01 dan DNS-01.

Pendekatan pertama (HTTP-01) adalah meluncurkan server web kecil dengan penyebaran terpisah, yang akan dikirim ke Internet melalui tautan <YOUR_DOMAIN > /. Terkenal / acme-challenge / <TOKEN> beberapa data yang diminta dari server sertifikasi. Oleh karena itu, metode ini menyiratkan ketersediaan Ingress dari luar pada port 80 dan resolusi catatan DNS domain ke alamat IP publik.

Pilihan kedua untuk memverifikasi sertifikat yang dikeluarkan (DNS-01) berasaldari memiliki API ke server DNS yang menampung catatan domain. Penerbit, menggunakan token yang ditunjukkan, membuat catatan TXT pada domain, yang kemudian diterima server ACME selama konfirmasi. Di antara penyedia DNS yang didukung secara resmi adalah CloudFlare, AWS Route53, Google CloudDNS dan lainnya, termasuk implementasinya sendiri ( acme-dns ).

Catatan : Let's Encrypt memiliki batasan yang cukup ketat pada permintaan ke server ACME. Agar tidak dicekal , disarankan untuk menggunakan tipe sertifikat letsencrypt-staging untuk debugging (perbedaannya hanya di server ACME).

Jadi, kami menggambarkan sumber daya:

apiVersion: cert-manager.io/v1alpha2
kind: Issuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory 
    privateKeySecretRef:
      name: letsencrypt
    solvers:
    - http01:
       ingress:
         class: nginx
---
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: le-crt
spec:
  secretName: tls-secret
  issuerRef:
    kind: Issuer
    name: letsencrypt
  commonName: yet-another.website
  dnsNames:
  - yet-another.website

Perhatikan bahwa alamat server pementasan ditentukan sebagai servery acme(c Issuer) . Menggantinya dengan pertempuran akan dimungkinkan nanti. Menerapkan konfigurasi ini, kami melacak seluruh jalur pesanan:



  1. Penciptaan Certificatemelahirkan sumber daya baru CertificateRequest:

    kubectl -n app describe certificate le-crt
    ...
    Created new CertificateRequest resource "le-crt-1127528680"
  2. Dalam deskripsinya - tanda pada ciptaan Order:

    kubectl -n app describe certificaterequests le-crt-1127528680
    Created Order resource app/le-crt-1127528680-1805948596
  3. Ini Ordermenjelaskan dengan parameter apa tes lulus dan apa status saat ini. Verifikasi semacam itu dilakukan oleh sumber Challenge:

    kubectl -n app describe order le-crt-1127528680-1805948596
    Created Challenge resource "le-crt-1127528680-1805948596-1231544594" for domain "yet-another.website"
  4. Akhirnya, perincian sumber daya ini memuat informasi tentang status pemindaian itu sendiri:

    kubectl -n app describe challenges le-crt-1127528680-1805948596-1231544594
    ...
      Reason:      Successfully authorized domain                                                                                                                                                                      
    ...
      Normal  Started         2m45s  cert-manager  Challenge scheduled for processing
      Normal  Presented       2m45s  cert-manager  Presented challenge using http-01 challenge mechanism
      Normal  DomainVerified  2m22s  cert-manager  Domain "yet-another.website" verified with "http-01" validation

Jika semua persyaratan telah dipenuhi (mis. Domain dapat diakses dari luar, tidak ada larangan dari LE ...) - dalam waktu kurang dari satu menit, sertifikat akan dikeluarkan. Jika berhasil, describe certificate le-crtcatatan akan muncul di output Certificate issued successfully.

Sekarang Anda dapat dengan aman mengubah alamat server untuk memerangi ( https://acme-v02.api.letsencrypt.org/directory) dan memesan kembali sertifikat asli yang sudah ditandatangani bukan Fake LE Intermediate X1, tetapi Let's Encrypt Authority X3.

Untuk melakukan ini, pertama-tama Anda harus menghapus sumber Certificate: jika tidak, prosedur pemesanan tidak diaktifkan, karena sertifikat sudah ada dan relevan. Menghapus rahasia akan mengarah ke pengembaliannya segera dengan pesan ke describe certificate:

  Normal  PrivateKeyLost  44s                   cert-manager  Lost private key for CertificateRequest "le-crt-613810377", deleting old resource

Tetap menerapkan manifesto "tempur" untuk Issueryang sudah dijelaskan di atas Certificate(itu belum berubah):

apiVersion: cert-manager.io/v1alpha2
kind: Issuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt
    solvers:
    - http01:
       ingress:
         class: nginx

Setelah menerima pesan Certificate issued successfully, describeperiksa:

kubectl -n app get secret tls-secret -ojson | jq -r '.data."tls.crt"' | base64 -d | openssl x509 -dates -noout -issuer
notBefore=Feb 10 21:11:48 2020 GMT
notAfter=May 10 21:11:48 2020 GMT
issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3

Nomor 3. Wildcard LE dengan validasi DNS


Kami akan menyulitkan tugas dengan segera menulis sertifikat ke semua subdomain situs dan menggunakan waktu ini untuk memeriksa DNS (melalui CloudFlare).

Pertama, dapatkan token di panel kontrol CloudFlare untuk bekerja melalui API:

  1. Profil → Token API → Buat Token.
  2. Tetapkan izin sebagai berikut:
    • Izin:
      • Zone - DNS - Edit
      • Zone - Zone - Baca
    • Sumber Daya Zona:
      • Sertakan - Semua Zona
  3. Salin token yang diterima setelah disimpan (misalnya :) y_JNkgQwkroIsflbbYqYmBooyspN6BskXZpsiH4M.

Buat sebuah Rahasia di mana token ini akan disimpan, dan merujuknya di Penerbit:

apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-token
type: Opaque
stringData:
  api-token: y_JNkgQwkroIsflbbYqYmBooyspN6BskXZpsiH4M
---
apiVersion: cert-manager.io/v1alpha2
kind: Issuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory 
    privateKeySecretRef:
      name: letsencrypt
    solvers:
    - dns01:
        cloudflare:
          email: my-cloudflare-acc@example.com
          apiTokenSecretRef:
            name: cloudflare-api-token
            key: api-token

---
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: le-crt
spec:
  secretName: tls-secret
  issuerRef:
    kind: Issuer
    name: letsencrypt
  commonName: yet-another.website
  dnsNames:
  - "yet-another.website"
  - "*.yet-another.website"

(Jangan lupa untuk menggunakan pementasan jika Anda sedang bereksperimen!)

Mari kita melalui proses mengonfirmasi kepemilikan domain:

kubectl -n app describe challenges.acme.cert-manager.io le-crt-613810377-1285319347-3806582233
...
Status:
  Presented:   true
  Processing:  true
  Reason:      Waiting for dns-01 challenge propagation: DNS record for "yet-another.website" not yet propagated
  State:       pending
Events:
  Type    Reason     Age   From          Message
  ----    ------     ----  ----          -------
  Normal  Started    54s   cert-manager  Challenge scheduled for processing
  Normal  Presented  53s   cert-manager  Presented challenge using dns-01 challenge mechanism

Data TXT akan muncul di panel:



... dan setelah beberapa saat statusnya akan berubah menjadi:

Domain "yet-another.website" verified with "dns-01" validation

Pastikan sertifikat itu valid untuk subdomain apa pun:

kubectl -n app get secret tls-secret -ojson | jq -r '.data."tls.crt"' | base64 -d | openssl x509 -dates -noout -text |grep DNS:
          DNS:*.yet-another.website, DNS:yet-another.website

Validasi oleh DNS, sebagai suatu peraturan, tidak terjadi dengan cepat, karena sebagian besar penyedia DNS memiliki periode pembaruan data yang menunjukkan berapa banyak waktu berlalu sejak saat catatan DNS diubah menjadi pembaruan aktual semua server DNS penyedia. Namun, standar ACME juga menyediakan kombinasi dua opsi verifikasi, yang dapat digunakan untuk mempercepat penerimaan sertifikat untuk domain utama. Dalam hal ini, uraiannya Issueradalah sebagai berikut:

apiVersion: cert-manager.io/v1alpha2
kind: Issuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt
    solvers:
    - selector:
        dnsNames:
        - "*.yet-another.website"
      dns01:
        cloudflare:
          email: my-cloudflare-acc@example.com
          apiTokenSecretRef:
            name: cloudflare-api-token
            key: api-token            
    - selector:
        dnsNames:
        - "yet-another.website"
      http01:
        ingress:
          class: nginx

Jika Anda menerapkan konfigurasi ini, dua sumber daya akan dibuat Challenge:

kubectl -n app describe orders le-crt-613810377-1285319347
  Normal  Created  3m29s  cert-manager  Created Challenge resource "le-crt-613810377-1285319347-3996324737" for domain "yet-another.website"                 
  Normal  Created  3m29s  cert-manager  Created Challenge resource "le-crt-613810377-1285319347-1443470517" for domain "yet-another.website"

Nomor 4 Menggunakan Anotasi Khusus Ingress


Selain jalur langsung untuk membuat sertifikat di cert-manager, dimungkinkan untuk menggunakan komponen yang disebut ingress-shim dan tidak secara eksplisit membuat sumber daya Certificate. Idenya adalah bahwa dengan bantuan anotasi Ingress khusus, sertifikat akan secara otomatis dipesan menggunakan yang ditunjukkan di dalamnya Issuer. Hasilnya kira-kira sumber daya Ingress berikut:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  tls:
  - hosts:
    - "yet-another.website"
    secretName: tls-secret
  rules:
  - host: "yet-another.website"
    http:
      paths:
      - path: /
        backend:
          serviceName: app
          servicePort: 8080

Untuk operasi yang benar, hanya kehadiran Emiten yang cukup di sini, yaitu membuat satu entitas kurang.

Selain itu, ada anotasi kube-lego usang , - , - yang memerlukan tugas default saat memasang cert-manager menggunakan parameter Helm (atau dalam opsi peluncuran wadah manajer). Kami di perusahaan tidak menggunakan opsi ini dan tidak dapat menyarankan mereka karena opacity dari pendekatan yang digunakan untuk memesan sertifikat SSL (dan pada saat yang sama untuk berbagai masalah yang muncul ), tetapi masih memutuskan untuk menyebutkan dalam artikel untuk gambaran yang lebih lengkap.kubernetes.io/tls-acme: "true"Issuer



Alih-alih sebuah kesimpulan


Melalui manipulasi sederhana dengan CRD, kami belajar cara menulis sertifikat SSL yang dapat diperpanjang secara otomatis, ditandatangani sendiri, dan gratis dari proyek Let's Encrypt untuk domain situs web yang diluncurkan sebagai bagian dari Ingresss di kluster Kubernetes.

Artikel ini memberikan contoh penyelesaian masalah yang paling umum dalam praktik kami. Namun, fungsi manajer sertifikat tidak terbatas pada fitur yang dijelaskan di atas. Di situs web utilitas, Anda dapat menemukan contoh bekerja dengan layanan lain - misalnya, bundel dengan Vault atau penggunaan pusat penerbit eksternal (penerbit).

PS


Baca juga di blog kami:


All Articles