mTLS हर जगह: APISIX के लिए TLS कैसे कॉन्फ़िगर करें

Nicolas Fränkel

Nicolas Fränkel

July 31, 2023

Ecosystem

संक्षेप में TLS

TLS कई क्षमताएं प्रदान करता है:

  • सर्वर प्रमाणीकरण: क्लाइंट को यह विश्वास होता है कि वह जिस सर्वर के साथ डेटा का आदान-प्रदान कर रहा है, वह सही है। यह गलत व्यक्ति को गोपनीय डेटा भेजने से बचाता है
  • वैकल्पिक क्लाइंट प्रमाणीकरण: इसके विपरीत, सर्वर केवल उन क्लाइंट्स को अनुमति देता है जिनकी पहचान सत्यापित की जा सकती है
  • गोपनीयता: कोई तीसरा पक्ष क्लाइंट और सर्वर के बीच आदान-प्रदान किए गए डेटा को नहीं पढ़ सकता है
  • अखंडता: कोई तीसरा पक्ष डेटा में छेड़छाड़ नहीं कर सकता है

TLS प्रमाणपत्रों के माध्यम से काम करता है। एक प्रमाणपत्र एक आईडी के समान होता है, जो प्रमाणपत्र धारक की पहचान साबित करता है। एक आईडी की तरह, आपको यह विश्वास करने की आवश्यकता है कि इसे किसने जारी किया है। विश्वास एक श्रृंखला के माध्यम से स्थापित होता है: यदि मैं एलिस पर विश्वास करता हूं, जो बॉब पर विश्वास करता है, जो बदले में चार्ली पर विश्वास करता है, जिसने प्रमाणपत्र जारी किया है, तो मैं उस प्रमाणपत्र पर विश्वास करता हूं। इस परिदृश्य में, एलिस को रूट प्रमाणपत्र प्राधिकरण के रूप में जाना जाता है।

TLS प्रमाणीकरण सार्वजनिक कुंजी क्रिप्टोग्राफी पर आधारित है। एलिस एक सार्वजनिक कुंजी/निजी कुंजी जोड़ी उत्पन्न करती है और सार्वजनिक कुंजी प्रकाशित करती है। यदि कोई सार्वजनिक कुंजी के साथ डेटा को एन्क्रिप्ट करता है, तो केवल वह निजी कुंजी जो सार्वजनिक कुंजी उत्पन्न करती है, उसे डिक्रिप्ट कर सकती है। दूसरा उपयोग यह है कि कोई निजी कुंजी के साथ डेटा को एन्क्रिप्ट करे और सार्वजनिक कुंजी वाले सभी इसे डिक्रिप्ट कर सकें, इस प्रकार उनकी पहचान साबित होती है।

अंत में, म्यूचुअल TLS, aka mTLS, दो-तरफ़ा TLS का कॉन्फ़िगरेशन है: सर्वर प्रमाणीकरण क्लाइंट के लिए, जैसा कि सामान्य है, लेकिन इसके विपरीत, क्लाइंट प्रमाणीकरण सर्वर के लिए।

अब हमारे पास इन अवधारणाओं को समझने के लिए पर्याप्त ज्ञान है ताकि हम इसे व्यावहारिक रूप से लागू कर सकें।

cert-manager के साथ प्रमाणपत्र उत्पन्न करना

कुछ रूट प्रमाणपत्र प्राधिकरण (Certificate Authorities) ब्राउज़रों में डिफ़ॉल्ट रूप से इंस्टॉल होते हैं। इस तरह हम HTTPS वेबसाइटों को सुरक्षित रूप से ब्राउज़ कर सकते हैं, यह विश्वास करते हुए कि https://apache.org वह साइट है जो वे होने का दावा करती है। इंफ्रास्ट्रक्चर में कोई पूर्व-इंस्टॉल प्रमाणपत्र नहीं होते हैं, इसलिए हमें शुरुआत से शुरू करना होगा।

हमें कम से कम एक रूट प्रमाणपत्र की आवश्यकता है। बदले में, यह अन्य सभी प्रमाणपत्र उत्पन्न करेगा। हालांकि इसे मैन्युअल रूप से करना संभव है, मैं Kubernetes में cert-manager का उपयोग करूंगा। जैसा कि इसके नाम से पता चलता है, cert-manager प्रमाणपत्रों को प्रबंधित करने के लिए एक समाधान है।

Helm के साथ इसे इंस्टॉल करना सरल है:

helm repo add jetstack https://charts.jetstack.io #1 helm install \ cert-manager jetstack/cert-manager \ --namespace cert-manager \ #2 --create-namespace \ #2 --version v1.11.0 \ --set installCRDs=true \ --set prometheus.enabled=false #3
  1. चार्ट्स का रिपॉजिटरी जोड़ें
  2. ऑब्जेक्ट्स को एक समर्पित नेमस्पेस में इंस्टॉल करें
  3. इस पोस्ट के दायरे में मॉनिटरिंग न करें

हम पॉड्स को देखकर यह सुनिश्चित कर सकते हैं कि सब कुछ ठीक से काम कर रहा है:

kubectl get pods -n cert-manager
cert-manager-cainjector-7f694c4c58-fc9bk 1/1 Running 2 (2d1h ago) 7d cert-manager-cc4b776cf-8p2t8 1/1 Running 1 (2d1h ago) 7d cert-manager-webhook-7cd8c769bb-494tl 1/1 Running 1 (2d1h ago) 7d

cert-manager कई स्रोतों से प्रमाणपत्रों पर हस्ताक्षर कर सकता है: HashiCorp Vault, Let's Encrypt, आदि। चीजों को सरल रखने के लिए:

  • हम अपना समर्पित रूट प्रमाणपत्र उत्पन्न करेंगे, यानी, Self-Signed
  • हम प्रमाणपत्र रोटेशन को संभालेंगे नहीं

आइए निम्नलिखित से शुरू करें:

apiVersion: cert-manager.io/v1 kind: ClusterIssuer #1 metadata: name: selfsigned-issuer spec: selfSigned: {} --- apiVersion: v1 kind: Namespace metadata: name: tls #2 --- apiVersion: cert-manager.io/v1 kind: Certificate #3 metadata: name: selfsigned-ca namespace: tls spec: isCA: true commonName: selfsigned-ca secretName: root-secret issuerRef: name: selfsigned-issuer kind: ClusterIssuer group: cert-manager.io --- apiVersion: cert-manager.io/v1 kind: Issuer #4 metadata: name: ca-issuer namespace: tls spec: ca: secretName: root-secret
  1. प्रमाणपत्र प्राधिकरण जो क्लस्टर-वाइड प्रमाणपत्र उत्पन्न करता है
  2. हमारे डेमो के लिए एक नेमस्पेस बनाएं
  3. क्लस्टर-वाइड इश्यूअर का उपयोग करके नेमस्पेस्ड रूट प्रमाणपत्र। केवल एक नेमस्पेस्ड इश्यूअर बनाने के लिए उपयोग किया जाता है
  4. नेमस्पेस्ड इश्यूअर। पोस्ट में अन्य सभी प्रमाणपत्र बनाने के लिए उपयोग किया जाता है

पिछले मैनिफेस्ट को लागू करने के बाद, हमें बनाए गए एकल प्रमाणपत्र को देखने में सक्षम होना चाहिए:

kubectl get certificate -n tls
NAME READY SECRET AGE selfsigned-ca True root-secret 7s

प्रमाणपत्र इंफ्रास्ट्रक्चर तैयार है; आइए Apache APISIX को देखें।

एक नमूना Apache APISIX आर्किटेक्चर का त्वरित अवलोकन

Apache APISIX एक API गेटवे है। डिफ़ॉल्ट रूप से, यह अपने कॉन्फ़िगरेशन को etcd में संग्रहीत करता है, एक वितरित की-वैल्यू स्टोर - वही जो Kubernetes द्वारा उपयोग किया जाता है। ध्यान दें कि वास्तविक दुनिया के परिदृश्यों में, हमें समाधान की लचीलापन बढ़ाने के लिए etcd क्लस्टरिंग सेट अप करना चाहिए। इस पोस्ट के लिए, हम खुद को एकल etcd इंस्टेंस तक सीमित रखेंगे। Apache APISIX HTTP एंडपॉइंट्स के माध्यम से एक एडमिन API प्रदान करता है। अंत में, गेटवे क्लाइंट से कॉल को एक अपस्ट्रीम में फॉरवर्ड करता है। यहां आर्किटेक्चर और आवश्यक प्रमाणपत्रों का एक अवलोकन दिया गया है:

Apache APISIX आर्किटेक्चर

आइए नींव के ईंटों से शुरू करें: etcd और Apache APISIX। हमें दो प्रमाणपत्रों की आवश्यकता है: एक etcd के लिए, सर्वर भूमिका में, और एक Apache APISIX के लिए, etcd क्लाइंट के रूप में।

आइए हमारे नेमस्पेस्ड इश्यूअर से प्रमाणपत्र सेट अप करें:

apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: etcd-server #1 namespace: tls spec: secretName: etcd-secret #2 isCA: false usages: - client auth #3 - server auth #3 dnsNames: - etcd #4 issuerRef: name: ca-issuer #5 kind: Issuer --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: apisix-client #6 namespace: tls spec: secretName: apisix-client-secret isCA: false usages: - client auth emailAddresses: - apisix@apache.org #7 issuerRef: name: ca-issuer #5 kind: Issuer
  1. etcd के लिए प्रमाणपत्र
  2. Kubernetes Secret नाम, नीचे देखें
  3. इस प्रमाणपत्र के लिए उपयोग
  4. Kubernetes Service नाम, नीचे देखें
  5. पहले बनाए गए नेमस्पेस्ड इश्यूअर का संदर्भ
  6. etcd के क्लाइंट के रूप में Apache APISIX के लिए प्रमाणपत्र
  7. क्लाइंट्स के लिए अनिवार्य विशेषता

उपरोक्त मैनिफेस्ट को लागू करने के बाद, हम tls नेमस्पेस में प्रमाणपत्रों की सूची देख सकते हैं:

kubectl get certificates -n tls
NAME READY SECRET AGE selfsigned-ca True root-secret 8m59s //1 apisix-client True apisix-client-secret 8m22s //2 etcd-server True etcd-secret 8m54s //2
  1. पहले बनाया गया प्रमाणपत्र
  2. selfsigned-ca द्वारा हस्ताक्षरित नए बनाए गए प्रमाणपत्र

cert-manager के प्रमाणपत्र

अब तक, हमने Certificate ऑब्जेक्ट्स बनाए हैं, लेकिन हमने यह नहीं समझाया है कि वे क्या हैं। वास्तव में, वे cert-manager द्वारा प्रदान किए गए साधारण Kubernetes CRDs हैं। पर्दे के पीछे, cert-manager एक Kubernetes Secret को Certificate से बनाता है। यह पूरे जीवनचक्र को प्रबंधित करता है, इसलिए एक Certificate को हटाने से संबंधित Secret भी हट जाता है। उपरोक्त मैनिफेस्ट में secretName विशेषता Secret नाम सेट करती है।

kubectl get secrets -n tls
NAME TYPE DATA AGE apisix-client-secret kubernetes.io/tls 3 35m etcd-secret kubernetes.io/tls 3 35m root-secret kubernetes.io/tls 3 35m

आइए एक Secret को देखें, जैसे, apisix-client-secret:

kubectl describe apisix-client-secret -n tls
Name: apisix-client-secret Namespace: tls Labels: controller.cert-manager.io/fao=true Annotations: cert-manager.io/alt-names: cert-manager.io/certificate-name: apisix-client cert-manager.io/common-name: cert-manager.io/ip-sans: cert-manager.io/issuer-group: cert-manager.io/issuer-kind: Issuer cert-manager.io/issuer-name: ca-issuer cert-manager.io/uri-sans: Type: kubernetes.io/tls Data ==== ca.crt: 1099 bytes tls.crt: 1115 bytes tls.key: 1679 bytes

एक Certificate द्वारा बनाया गया Secret तीन विशेषताएं प्रदान करता है:

  • tls.crt: प्रमाणपत्र स्वयं
  • tls.key: निजी कुंजी
  • ca.crt: प्रमाणपत्र श्रृंखला में हस्ताक्षर करने वाला प्रमाणपत्र, यानी, root-secret/tls.crt

Kubernetes Secret सामग्री को base 64 में एन्कोड करता है। उपरोक्त में से किसी को सादे पाठ में प्राप्त करने के लिए, इसे डिकोड करना होगा, जैसे:

kubectl get secret etcd-secret -n tls -o jsonpath='{ .data.tls\.crt }' | base64
-----BEGIN CERTIFICATE----- MIIDBjCCAe6gAwIBAgIQM3JUR8+R0vuUndjGK/aOgzANBgkqhkiG9w0BAQsFADAY MRYwFAYDVQQDEw1zZWxmc2lnbmVkLWNhMB4XDTIzMDMxNjEwMTYyN1oXDTIzMDYx NDEwMTYyN1owADCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQpMj/0 giDVOjOosSRRKUwTzl1Wo2R9YYAeteOW3fuMiAd+XaBGmRO/+GWZQN1tyRQ3pITM ezBgogYAUUNcuqN/UAsgH/JM58niMjZdjRKn4+it94Nj1e24jFL4ts2snCn7FfKJ 3zRtY9tyS7Agw3tCwtXV68Xpmf3CsfhPmn3rGdWHXyYctzAZhqYfEswN3hxpJZxR YVeb55WgDoPo5npZo3+yYiMtoOimIprcmZ2Ye8Wai9S4QKDafUWlvU5GQ65VVLzH PEdOMwbWcwiLqwUv889TiKiC5cyAD6wJOuPRF0KKxxFnG+lHlg9J2S1i5sC3pqoc i0pEQ+atOOyLMMECAwEAAaNkMGIwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF BwMBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAU2ZaAdEficKUWPFRjdsKSEX/l gbMwEgYDVR0RAQH/BAgwBoIEZXRjZDANBgkqhkiG9w0BAQsFAAOCAQEABcNvYTm8 ZJe3jUq6f872dpNVulb2UvloTpWxQ8jwXgcrhekSKU6pZ4p9IPwfauHLjceMFJLp t2eDi5fSQ1upeqXOofeyKSYjjyA/aVf1zMI8ReCCQtQuAVYyJWBlNLc3XMMecbcp JLGtd/OAZnKDeYYkUX7cJ2wN6Wl/wGLM2lxsqDhEHEZwvGL0DmsdHw7hzSjdVmxs 0Qgkh4jVbNUKdBok5U9Ivr3P1xDPaD/FqGFyM0ssVOCHxtPxhOUA/m3DSr6klfEF McOfudZE958bChOrJgVrUnY3inR0J335bGQ1luEp5tYwPgyD9dG4MQEDD3oLwp+l +NtTUqz8WVlMxQ== -----END CERTIFICATE-----

etcd और APISIX के बीच mTLS कॉन्फ़िगर करना

प्रमाणपत्र उपलब्ध होने के साथ, हम अब etcd और APISIX के बीच म्यूचुअल TLS कॉन्फ़िगर कर सकते हैं। आइए etcd से शुरू करें:

apiVersion: v1 kind: Pod metadata: name: etcd namespace: tls labels: role: config spec: containers: - name: etcd image: bitnami/etcd:3.5.7 ports: - containerPort: 2379 env: - name: ETCD_TRUSTED_CA_FILE #1 value: /etc/ssl/private/ca.crt - name: ETCD_CERT_FILE #2 value: /etc/ssl/private/tls.crt - name: ETCD_KEY_FILE #3 value: /etc/ssl/private/tls.key - name: ETCD_ROOT_PASSWORD value: whatever - name: ETCD_CLIENT_CERT_AUTH #4 value: "true" - name: ETCD_LISTEN_CLIENT_URLS value: https://0.0.0.0:2379 volumeMounts: - name: ssl mountPath: /etc/ssl/private #5 volumes: - name: ssl secret: secretName: etcd-secret #5
  1. विश्वसनीय CA सेट करें
  2. प्रमाणपत्र सेट करें
  3. निजी कुंजी सेट करें
  4. क्लाइंट्स को अपना प्रमाणपत्र पास करने की आवश्यकता है, इस प्रकार म्यूचुअल प्रमाणीकरण सुनिश्चित करें
  5. कंटेनर में पहले से उत्पन्न सीक्रेट को माउंट करें

अब, Apache APISIX की बारी है:

apiVersion: v1 kind: ConfigMap #1 metadata: name: apisix-config namespace: tls data: config.yaml: >- apisix: ssl: ssl_trusted_certificate: /etc/ssl/certs/ca.crt #2 deployment: etcd: host: - https://etcd:2379 tls: cert: /etc/ssl/certs/tls.crt #2 key: /etc/ssl/certs/tls.key #2 admin: allow_admin: - 0.0.0.0/0 https_admin: true #3 admin_api_mtls: admin_ssl_cert: /etc/ssl/private/tls.crt #3 admin_ssl_cert_key: /etc/ssl/private/tls.key #3 admin_ssl_ca_cert: /etc/ssl/private/ca.crt #3 --- apiVersion: v1 kind: Pod metadata: name: apisix namespace: tls labels: role: gateway spec: containers: - name: apisix image: apache/apisix:3.2.0-debian ports: - containerPort: 9443 #4 - containerPort: 9180 #5 volumeMounts: - name: config #1 mountPath: /usr/local/apisix/conf/config.yaml subPath: config.yaml - name: ssl #6 mountPath: /etc/ssl/private - name: etcd-client #7 mountPath: /etc/ssl/certs volumes: - name: config configMap: name: apisix-config - name: ssl #6,8 secret: secretName: apisix-server-secret - name: etcd-client #7,8 secret: secretName: apisix-client-secret
  1. Apache APISIX पर्यावरण चर के माध्यम से कॉन्फ़िगरेशन की अनुमति नहीं देता है। हमें एक ConfigMap का उपयोग करने की आवश्यकता है जो नियमित config.yaml फ़ाइल को दर्पण करता है
  2. etcd के लिए क्लाइंट प्रमाणीकरण कॉन्फ़िगर करें
  3. एडमिन API के लिए सर्वर प्रमाणीकरण कॉन्फ़िगर करें
  4. नियमित HTTPS पोर्ट
  5. एडमिन HTTPS पोर्ट
  6. सर्वर प्रमाणीकरण के लिए प्रमाणपत्र
  7. क्लाइंट प्रमाणीकरण के लिए प्रमाणपत्र
  8. दो सेट प्रमाणपत्रों का उपयोग किया जाता है, एक एडमिन API और नियमित HTTPS के लिए सर्वर प्रमाणीकरण के लिए, और एक etcd के लिए क्लाइंट प्रमाणीकरण के लिए।

इस बिंदु पर, हम उपरोक्त मैनिफेस्ट को लागू कर सकते हैं और दो पॉड्स को संचार करते हुए देख सकते हैं। जब कनेक्ट होता है, तो Apache APISIX HTTPS के माध्यम से अपना apisix-client प्रमाणपत्र भेजता है। क्योंकि एक प्राधिकरण प्रमाणपत्र पर हस्ताक्षर करता है जिस पर etcd विश्वास करता है, यह कनेक्शन की अनुमति देता है।

मैंने संक्षिप्तता के लिए Service परिभाषा को छोड़ दिया है, लेकिन आप उन्हें संबंधित GitHub रिपॉजिटरी में देख सकते हैं।

NAME READY STATUS RESTARTS AGE apisix 1/1 Running 0 179m etcd 1/1 Running 0 179m

क्लाइंट एक्सेस

अब जब हमने बुनियादी इंफ्रास्ट्रक्चर सेट कर लिया है, तो हमें इसे एक क्लाइंट के साथ एक्सेस करने का परीक्षण करना चाहिए। हम अपने विश्वसनीय curl का उपयोग करेंगे, लेकिन कोई भी क्लाइंट जो प्रमाणपत्रों को कॉन्फ़िगर करने की अनुमति देता है, काम करेगा, जैसे, httpie।

पहला कदम क्लाइंट के लिए एक समर्पित प्रमाणपत्र-कुंजी जोड़ी बनाना है:

apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: curl-client namespace: tls spec: secretName: curl-secret isCA: false usages: - client auth emailAddresses: - curl@localhost.dev issuerRef: name: ca-issuer kind: Issuer

curl को प्रमाणपत्र फ़ाइल के पथ की आवश्यकता होती है, सामग्री के बजाय। हम zsh के जादू के माध्यम से इस सीमा को पार कर सकते हैं: =( ... ) सिंटैक्स एक अस्थायी फ़ाइल बनाने की अनुमति देता है। यदि आप किसी अन्य शेल का उपयोग कर रहे हैं, तो आपको समकक्ष सिंटैक्स ढूंढना होगा या फ़ाइलों को मैन्युअल रूप से डाउनलोड करना होगा।

आइए एडमिन API को सभी मौजूदा रूट्स के लिए क्वेरी करें। यह सरल कमांड यह जांचने की अनुमति देता है कि Apache APISIX etcd से जुड़ा है, और यह वहां से अपना कॉन्फ़िगरेशन पढ़ सकता है।

curl --resolve 'admin:32180:127.0.0.1' https://admin:32180/apisix/admin/routes \ #1 --cert =(kubectl get secret curl-secret -n tls -o jsonpath='{ .data.tls\.crt }' | base64 -d) \ #2 --key =(kubectl get secret curl-secret -n tls -o jsonpath='{ .data.tls\.key }' | base64 -d) \ #2 --cacert =(kubectl get secret curl-secret -n tls -o jsonpath='{ .data.ca\.crt }' | base64 -d) \ #2 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1'
  1. --resolve /etc/hosts फ़ाइल को प्रदूषित करने से बचाता है। curl admin को localhost में अनुवाद करेगा, लेकिन क्वेरी Kubernetes क्लस्टर के अंदर admin को भेजी जाती है, इस प्रकार सही Service का उपयोग करती है
  2. Secret के अंदर आवश्यक डेटा प्राप्त करें, इसे डिकोड करें, और इसे एक अस्थायी फ़ाइल के रूप में उपयोग करें

यदि सब कुछ काम करता है, और यह करना चाहिए, तो परिणाम निम्नलिखित होना चाहिए:

{"total":0,"list":[]}

अभी तक कोई रूट उपलब्ध नहीं है क्योंकि हमने अभी तक कोई नहीं बनाया है।

अपस्ट्रीम के साथ TLS

अंतिम लेकिन कम से कम, हमें अपस्ट्रीम के लिए TLS कॉन्फ़िगर करना चाहिए। निम्नलिखित में, मैं एक सरल nginx इंस्टेंस का उपयोग करूंगा जो स्थिर सामग्री के साथ प्रतिक्रिया देता है। इसे अधिक जटिल अपस्ट्रीम के लिए एक उदाहरण के रूप में उपयोग करें।

पहला कदम, हमेशा की तरह, अपस्ट्रीम के लिए एक समर्पित Certificate उत्पन्न करना है। मैं इसे upstream-server कहूंगा और इसका Secret, अकल्पनीय रूप से, upstream-secret। अब हम बाद वाले का उपयोग NGINX को सुरक्षित करने के लिए कर सकते हैं:

apiVersion: v1 kind: ConfigMap #1 metadata: name: nginx-config namespace: tls data: nginx.conf: >- events { worker_connections 1024; } http { server { listen 443 ssl; server_name upstream; ssl_certificate /etc/ssl/private/tls.crt; #2 ssl_certificate_key /etc/ssl/private/tls.key; #2 root /www/data; location / { index index.json; } } } --- apiVersion: v1 kind: Pod metadata: name: upstream namespace: tls labels: role: upstream spec: containers: - name: upstream image: nginx:1.23-alpine ports: - containerPort: 443 volumeMounts: - name: config mountPath: /etc/nginx/nginx.conf #1 subPath: nginx.conf - name: content mountPath: /www/data/index.json #3 subPath: index.json - name: ssl #2 mountPath: /etc/ssl/private volumes: - name: config configMap: name: nginx-config - name: ssl #2 secret: secretName: upstream-secret - name: content #3 configMap: name: nginx-content
  1. NGINX पर्यावरण चर के माध्यम से कॉन्फ़िगरेशन की अनुमति नहीं देता है; हमें ConfigMap दृष्टिकोण का उपयोग करने की आवश्यकता है
  2. Certificate द्वारा बनाए गए कु
Tags: