mTLS Everywhere: How to Configure TLS for APISIX

Nicolas Fränkel

Nicolas Fränkel

July 31, 2023

Ecosystem

TLS باختصار

TLS توفر عدة إمكانيات:

  • مصادقة الخادم: يتأكد العميل من أن الخادم الذي يتبادل البيانات معه هو الخادم الصحيح. هذا يمنع إرسال البيانات، التي قد تكون سرية، إلى جهة خاطئة.
  • مصادقة العميل الاختيارية: بالعكس، يسمح الخادم فقط للعملاء الذين يمكن التحقق من هويتهم.
  • السرية: لا يمكن لأي طرف ثالث قراءة البيانات المتبادلة بين العميل والخادم.
  • التكامل: لا يمكن لأي طرف ثالث التلاعب بالبيانات.

يعمل TLS من خلال الشهادات. الشهادة تشبه بطاقة الهوية، تثبت هوية حامل الشهادة. تمامًا مثل بطاقة الهوية، يجب أن تثق في الجهة التي أصدرتها. يتم بناء الثقة من خلال سلسلة: إذا كنت أثق بـ "أليس"، التي تثق بـ "بوب"، الذي يثق بـ "تشارلي"، الذي أصدر الشهادة، فأنا أثق بهذه الشهادة. في هذا السيناريو، تُعرف "أليس" باسم سلطة الشهادات الجذرية.

تعتمد مصادقة TLS على تشفير المفتاح العام. تقوم "أليس" بإنشاء زوج من المفاتيح (مفتاح عام/مفتاح خاص) وتنشر المفتاح العام. إذا قام أحد بتشفير البيانات باستخدام المفتاح العام، فإن المفتاح الخاص الذي أنشأ المفتاح العام هو الوحيد الذي يمكنه فك التشفير. الاستخدام الآخر هو تشفير البيانات باستخدام المفتاح الخاص، ويمكن لأي شخص لديه المفتاح العام فك التشفير، مما يثبت هويته.

أخيرًا، TLS المتبادل، المعروف أيضًا باسم mTLS، هو تكوين TLS ثنائي الاتجاه: مصادقة الخادم للعميل كالمعتاد، ولكن أيضًا مصادقة العميل للخادم.

لدينا الآن فهم كافٍ للمفاهيم لنبدأ في التطبيق العملي.

إنشاء الشهادات باستخدام cert-manager

يتم تثبيت عدد من سلطات الشهادات الجذرية في المتصفحات بشكل افتراضي. هذه هي الطريقة التي يمكننا من خلالها تصفح مواقع HTTPS بأمان، مع الثقة بأن https://apache.org هو الموقع الذي يدعي أنه كذلك. البنية التحتية لا تحتوي على شهادات مثبتة مسبقًا، لذا يجب أن نبدأ من الصفر.

نحتاج إلى شهادة جذر واحدة على الأقل. بدورها، ستقوم بإنشاء جميع الشهادات الأخرى. بينما يمكن القيام بكل شيء يدويًا، سأعتمد على cert-manager في Kubernetes. كما يوحي اسمه، 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. إضافة مستودع Charts
  2. تثبيت الكائنات في مساحة اسم مخصصة
  3. عدم المراقبة، في نطاق هذا المنشور

يمكننا التأكد من أن كل شيء يعمل كما هو متوقع من خلال النظر إلى الـ pods:

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. أخيرًا، تقوم البوابة بتوجيه المكالمات من العميل إلى upstream. إليك نظرة عامة على البنية والشهادات المطلوبة:

بنية 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. اسم Secret في Kubernetes، انظر أدناه
  3. استخدامات هذه الشهادة
  4. اسم Service في Kubernetes، انظر أدناه
  5. الإشارة إلى المُصدر في مساحة الاسم الذي تم إنشاؤه مسبقًا
  6. شهادة لـ Apache APISIX كعميل لـ etcd
  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، ولكننا لم نشرح ما هي. في الواقع، هي ببساطة تعريفات موارد مخصصة (CRD) في Kubernetes مقدمة من cert-manager. تحت الغطاء، يقوم cert-manager بإنشاء Secret في Kubernetes من 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

يوفر Secret الذي تم إنشاؤه بواسطة Certificate ثلاث سمات:

  • 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-----

تكوين mTLS بين etcd و APISIX

مع توفر الشهادات، يمكننا الآن تكوين TLS المتبادل بين etcd و APISIX. لنبدأ بـ 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. تحميل Secret الذي تم إنشاؤه مسبقًا في الحاوية للوصول

الآن، حان دور 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. تكوين مصادقة الخادم لواجهة برمجة التطبيقات الإدارية
  4. منفذ HTTPS العادي
  5. منفذ HTTPS الإداري
  6. الشهادات لمصادقة الخادم
  7. الشهادات لمصادقة العميل
  8. يتم استخدام مجموعتين من الشهادات، واحدة لمصادقة الخادم لواجهة برمجة التطبيقات الإدارية و HTTPS العادي، وواحدة لمصادقة العميل لـ etcd.

في هذه المرحلة، يمكننا تطبيق البيانات أعلاه ورؤية الـ pods يتواصلون. عند الاتصال، يرسل Apache APISIX شهادة apisix-client عبر HTTPS. لأن الشهادة موقعة من قبل سلطة تثق بها 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: بناء الجملة =( ... ) يسمح بإنشاء ملف مؤقت. إذا كنت تستخدم shell آخر، فستحتاج إلى العثور على بناء الجملة المكافئ أو تنزيل الملفات يدويًا.

لنستعلم عن واجهة برمجة التطبيقات الإدارية لجميع المسارات الموجودة. هذا الأمر البسيط يسمح بالتحقق من أن 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، ولكن يتم إرسال الاستعلام إلى admin داخل مجموعة Kubernetes، وبالتالي استخدام Service الصحيح
  2. الحصول على البيانات المطلوبة داخل Secret، وفك تشفيرها، واستخدامها كملف مؤقت

إذا كان كل شيء يعمل، ويجب أن يعمل، يجب أن تكون النتيجة كما يلي:

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

لا توجد مسارات متاحة حتى الآن لأننا لم نقم بإنشاء أي منها.

TLS مع Upstreams

أخيرًا وليس آخرًا، يجب علينا تكوين TLS لـ upstreams. في ما يلي، سأستخدم نسخة بسيطة من nginx تستجيب بمحتوى ثابت. استخدمها كتوضيح لـ upstreams أكثر تعقيدًا.

الخطوة الأولى، كما هو الحال دائمًا، هي إنشاء Certificate مخصص لـ upstream. سأتخطى كيفية القيام بذلك لأننا أنشأنا بالفعل عددًا قليلاً. أسميها 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
  3. بعض المحتوى الثابت غير المهم في نطاق هذا المنشور

الخطوة التالية هي إنشاء المسار بمساعدة واجهة برمجة التطبيقات الإدارية. لقد أعددنا كل شيء في الخطوة السابقة؛ الآن يمكننا استخدام الواجهة:

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) \     #1
     --key =(kubectl get secret curl-secret -n tls -o jsonpath='{ .data.tls\.key }' | base64 -d) \      #1
     --cacert =(kubectl get secret curl-secret -n tls -o jsonpath='{ .data.ca\.crt }' | base64 -d) \    #1
     -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d "{
        \"uri\": \"/\",
        \"upstream\": {
          \"scheme\": \"https\",                                                                        #2
          \"nodes\": {
            \"upstream:443\": 1
          },
          \"tls\": {
            \"client_cert\": \"$(kubectl get secret curl-secret -n tls -o jsonpath='{ .data.tls\.crt }' | base64 -d)\", #3
            \"client_key\": \"$(kubectl get secret curl-secret -n tls -o jsonpath='{ .data.tls\.key }' | base64 -d)\"   #3
          }
        }
     }"
  1. مصادقة العميل لواجهة برمجة التطبيقات الإدارية، كما هو مذكور أعلاه
  2. استخدام HTTPS لـ upstream
  3. تكوين زوج المفتاح-الشهادة للمسار. يقوم Apache APISIX بتخزين البيانات في etcd وسيستخدمها عند استدعاء المسار. بدلاً من ذلك، يمكنك الاحتفاظ بالزوج ككائن مخصص واستخدام المرجع الذي تم إنشاؤه حديثًا (تمامًا كما هو الحال مع upstreams). يعتمد ذلك على عدد المسارات التي تحتاجها الشهادة. لمزيد من المعلومات، تحقق من نقطة نهاية SSL

أخيرًا، يمكننا التحقق من أنها تعمل كما هو متوقع:

curl --resolve 'upstream:32443:127.0.0.1' https://upstream:32443/ \
     --cert =(kubectl get secret curl-secret -n tls -o jsonpath='{ .data.tls\.crt }' | base64 -d) \
     --key =(kubectl get secret curl-secret -n tls -o jsonpath='{ .data.tls\.key }' | base64 -d) \
     --cacert =(kubectl get secret curl-secret -n tls -o jsonpath='{ .data.ca\.crt }' | base64 -d)

وهي تعمل:

{ "hello": "world" }

الخلاصة

في هذا المنشور، وصفت بنية عمل Apache APISIX وقمت بتنفيذ TLS المتبادل بين جميع المكونات: etcd و APISIX، العميل و APISIX، وأخيرًا، العميل و upstream. آمل أن يساعدك هذا على تحقيق نفس الشيء.

اتصل بنا إذا كان لديك أي أسئلة أو استفسارات حول APISIX وإدارة API.

للمضي قدمًا:

Tags: