אחסון סודות של Cassandra ב-Hashicorp Vault

אחסון סודות של Cassandra ב-Hashicorp Vault

התכונה הזו מאפשרת לכם לאחסן את פרטי הכניסה של Cassandra DB ל-Apigee Hybrid ב-Hashicorp Vault, כלי חיצוני לניהול סודות. מנהלי סודות חיצוניים מאפשרים לכם לנהל את אופן האחסון של סודות ב-Kubernetes, כולל ניהול של מיקום הנתונים ובקרת גישה ברמת פירוט גבוהה.

לפני גרסה 1.10 של Apigee Hybrid, הדרך היחידה לספק סיסמאות למשתמשי Cassandra הייתה לציין את הסיסמה ב-overrides.yaml. הסיסמאות האלה מאוחסנות בסודות של Kubernetes. לדוגמה:

cassandra:
  auth:
    default:
      password: "********"
    admin:
      password: "********"
    ddl:
      password: "********"
    dml:
      password: "********"
    jmx:
      username: "jmxuser"
      password: "********"
    jolokia:
      username: "apigee"
      password: "********"

באמצעות Hashicorp Vault, אתם יכולים לספק את הסיסמאות האלה דרך ה-API של מנהל התקן ה-CSI של Kubernetes Secrets Store‏ (SecretProviderClass). כך Kubernetes יכול לטעון כמה סודות, מפתחות ואישורים שמאוחסנים ב-Vault חיצוני.

משתמשים וסיסמאות ב-Cassandra

תצטרכו ליצור סודות למשתמשי Cassandra הבאים. משנים את ערכי ברירת המחדל כדי לעמוד בדרישות של מדיניות האבטחה של הארגון.

משתמש Cassandra שם משתמש שמוגדר כברירת מחדל סיסמת ברירת מחדל
אדמין admin_user "********"
DDL ddl_user "********"
ברירת מחדל cassandra הערה: שם המשתמש שמוגדר כברירת מחדל חייב להיות תמיד "cassandra" "********"
DML dml_user "********"
JMX "jmxuser" "********"
Jolokia "apigee" "********"

מידע נוסף זמין במאמר מאפיין ההגדרה של cassandra.

הגדרת שילוב של סודות חיצוניים

כדי להגדיר את השילוב של Vault ב-Apigee Hybrid, צריך לבצע את הפעולות הבאות.

  • בשני התהליכים הראשונים, אתם מבצעים פעולות ישירות ב-Vault.
  • בפרוצדורה השלישית והרביעית, מחילים את ההגדרות על אשכול Kubernetes.

כדי ליצור את הסודות ב-Vault ולאפשר להתקנה ההיברידית לגשת אליהם, צריך לבצע את הפעולות הבאות.

יצירת סודות, כללי מדיניות ותפקידים ב-Vault

  1. מוודאים שההקשר הנוכחי של Kubernetes מוגדר לאשכול:
    kubectl config current-context
  2. משתמשים ב-API, ב-CLI או בממשק המשתמש של Vault כדי ליצור את הסודות של Cassandra. ערכי הסודות שיוצרים צריכים להיות זהים לשמות המשתמשים והסיסמאות של Cassandra שמשמשים כרגע באשכול.
    • מפתח סודי: אפשר להשתמש בכל מפתח סודי (או בשילוב של כמה מפתחות), למשל:
      secret/data/apigee/cassandra
    • נתונים סודיים: ב-Apigee Hybrid צריך להזין זוגות של שם משתמש וסיסמה למשתמשי Cassandra הבאים:
      משתמשי Cassandra
      אדמין
      DDL
      ברירת מחדל
      DML
      JMX
      Jolokia
      אפשר לפזר את הערכים האלה של שם המשתמש והסיסמה על פני כל מספר של מפתחות סודיים.
    • Vault CLI: הפקודה הבאה מראה איך ליצור סוד יחיד שמכיל את כל שמות המשתמשים והסיסמאות הנדרשים:
      vault kv put secret/apigee/cassandra \
          adminUsername="ADMIN_USERNAME" \
          adminPassword="ADMIN_PASSWORD" \
          ddlUsername="DDL_USERNAME" \
          ddlPassword="DDL_PASSWORD" \
          defaultUsername="cassandra" \
          defaultPassword="DEFAULT_PASSWORD" \
          dmlUsername="DML_USERNAME" \
          dmlPassword="DML_PASSWORD" \
          jmxUsername="JMX_USERNAME" \
          jmxPassword="JMX_PASSWORD" \
          jolokiaUsername="JOLOKIA_USERNAME" \
          jolokiaPassword="JOLOKIA_PASSWORD"
      שמות המשתמשים שמוגדרים כברירת מחדל לכל משתמש הם:
      משתמש Cassandra ערך ברירת המחדל
      אדמין admin_user
      DDL ddl_user
      ברירת מחדל cassandra
      DML dml_user
      JMX jmxuser
      Jolokia apigee
  3. ב-Vault, יוצרים מדיניות כדי להעניק גישה לסוד שיצרתם.
    1. יוצרים קובץ מדיניות (שם מוצע: apigee-cassandra-auth.txt) עם התוכן הבא:
      path "secret/data/apigee/cassandra" {
        capabilities = ["read"]
      }
      אם יצרתם כמה סודות, צריך להוסיף כל אחד מהם לקובץ המדיניות:
      path "secret/data/apigee/cassandra/admin" {
        capabilities = ["read"]
      }
      
      path "secret/data/apigee/cassandra/ddl" {
        capabilities = ["read"]
      }
    2. מחילים את המדיניות על Vault:
      vault policy write apigee-cassandra-auth apigee-cassandra-auth.txt

      אפשר ליצור את המדיניות באמצעות קלט רגיל במקום לקרוא מקובץ:

      echo 'path "secret/data/apigee/cassandra" { capabilities = ["read"] }' | vault policy write apigee-cassandra-auth -
  4. מקשרים את המדיניות לחשבונות השירות של Apigee Cassandra Kubernetes.
    1. מגדירים את משתני הסביבה הבאים:
      export ORG_NAME=APIGEE_ORG_NAME
      export ENVS_LIST=LIST_OF_APIGEE-ENVS
      export APIGEE_NAMESPACE=YOUR_APIGEE_NAMESPACE

      כאשר:

      • ‫ORG_NAME הוא השם של הארגון ב-Apigee.
      • ‫ENVS_LIST היא רשימה מופרדת בפסיקים של סביבות Apigee, לדוגמה dev,prod.
      • ‫APIGEE_NAMESPACE הוא מרחב השמות של Apigee. ערך ברירת המחדל הוא apigee.
    2. יוצרים סקריפט עם התוכן הבא. התסריט יכול להיות בכל שם. בדוגמה הבאה, שם הסקריפט הוא create-vault-cassandra-role.sh:
      # create-vault-cassandra-role.sh
      
      ORG=ORG_NAME  # ORG name
      ENVS=ENVS_LIST # comma separated env names, for example: dev,prod
      
      org_short_name=$(echo $ORG | head -c 15)
      encode=$(echo -n $ORG | shasum -a 256 | head -c 7)
      org_encode=$(echo "$org_short_name-$encode")
      names=apigee-manager,apigee-cassandra-guardrails-sa,apigee-cassandra-default,apigee-cassandra-backup-sa,apigee-cassandra-restore-sa,apigee-cassandra-schema-setup-${org_encode},apigee-cassandra-schema-val-${org_encode},apigee-cassandra-user-setup-${org_encode},apigee-mart-${org_encode},apigee-mint-task-scheduler-${org_encode}
      
      for env in ${ENVS//,/ }
      do
        env_short_name=$(echo $env | head -c 15)
        encode=$(echo -n $ORG:$env | shasum -a 256 | head -c 7)
        env_encode=$(echo "$org_short_name-$env_short_name-$encode")
        names+=,apigee-synchronizer-${env_encode},apigee-runtime-${env_encode}
      done
      
      echo $names
      
    3. מריצים את הסקריפט ומקצים את הפלט למשתנה SERVICE_ACCOUNT_NAMES. הפעולה הזו תיצור רשימה מופרדת בפסיקים של שמות חשבונות שירות של Kubernetes.
      export SERVICE_ACCOUNT_NAMES=$(./create-vault-cassandra-role)

      מוודאים שהמשתנה אוכלס ברשימה:

      echo $SERVICE_ACCOUNT_NAMES
    4. משתמשים ב-CLI של Vault כדי ליצור תפקיד שמקשר את המדיניות לחשבונות השירות של Kubernetes:
      vault write auth/kubernetes/role/cassandra \
          bound_service_account_names=${SERVICE_ACCOUNT_NAMES} \
          bound_service_account_namespaces=${APIGEE_NAMESPACE} \
          policies=apigee-cassandra-auth \
          ttl=1m

התקנת מנהל התקן CSI וספק Vault

‫Apigee hybrid v1.16.11 תומך בגרסאות הבאות של תרשימי Helm:

תוכנה גרסה
Secrets Store CSI Driver v1.4.1
Vault 1.16.2
  1. פועלים לפי ההוראות להתקנת מנהל התקן CSI של Secrets Store כדי להתקין את מנהל התקן CSI באשכול. לדרייבר CSI יש תרשים Helm להתקנה.
  2. אם עדיין לא התקנתם את ספק ה-CSI של Vault, פועלים לפי ההוראות במאמר התקנת ספק ה-CSI של Vault.

יצירת אובייקט SecretProviderClass

המשאב SecretProviderClass מציין לדרייבר CSI עם איזה ספק ליצור קשר כשמבקשים סודות. צריך להגדיר את פרטי הכניסה של משתמשי Cassandra דרך האובייקט הזה. בטבלה הבאה מוצגים שמות הקבצים (objectNames) ש-Apigee Cassandra מצפה להם:

משתמש Cassandra שמות הקבצים הצפויים של הסודות
אדמין adminUsername, adminPassword
DDL ddlUsername, ddlPassword
ברירת מחדל cassandra, defaultPassword
DML dmlUsername, dmlPassword
JMX jmxUsername, jmxPassword
Jolokia jolokiaUsername, jolokiaPassword
  1. יוצרים קובץ YAML בשביל SecretProviderClass. אפשר לבחור כל שם לקובץ, למשל: spc.yaml. כדי להגדיר את המשאב הזה, משתמשים בתבנית SecretProviderClass הבאה:
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: apigee-cassandra-auth-spc
    spec:
      provider: vault
      parameters:
        roleName: apigee-cassandra-auth  # the roleName should match the vault role you created earlier in this procedure
    
        # vaultAddress is the endpoint your Vault server is running at.
        # If Vault is running in the same cluster as Apigee, the format will generally be:
        # http://vault.<namespace>.svc.cluster.local:<vaultServicePort>
        vaultAddress: VAULT_ADDRESS
    
        # "objectName" is an alias used within the SecretProviderClass to reference
        # that specific secret. This will also be the filename containing the secret.
        # Apigee Cassandra expects these exact values so they must not be changed.
        # "secretPath" is the path in Vault where the secret should be retrieved.
        # "secretKey" is the key within the Vault secret response to extract a value from.
        # For example, if the Vault secret is located at `secret/data/apigee/cassandra`
        # and you want to specify the admin password, you would use the following:
        # - objectName: "adminPassword"
        #   secretPath: "secret/data/apigee/cassandra"
        #   secretKey: "key within Vault secret specifying the admin password"
        objects: |
          - objectName: "adminUsername"
            secretPath: ""
            secretKey: ""
          - objectName: "adminPassword"
            secretPath: ""
            secretKey: ""
          - objectName: "defaultUsername"
            secretPath: ""
            secretKey: ""
          - objectName: "defaultPassword"
            secretPath: ""
            secretKey: ""
          - objectName: "ddlUsername"
            secretPath: ""
            secretKey: ""
          - objectName: "ddlPassword"
            secretPath: ""
            secretKey: ""
          - objectName: "dmlUsername"
            secretPath: ""
            secretKey: ""
          - objectName: "dmlPassword"
            secretPath: ""
            secretKey: ""
          - objectName: "jolokiaUsername"
            secretPath: ""
            secretKey: ""
          - objectName: "jolokiaPassword"
            secretPath: ""
            secretKey: ""
          - objectName: "jmxUsername"
            secretPath: ""
            secretKey: ""
          - objectName: "jmxPassword"
            secretPath: ""
            secretKey: ""
  2. מחילים את SecretProviderClass על מרחב השמות apigee:
    kubectl -n $APIGEE_NAMESPACE apply -f spc.yaml

הפעלת סוד חיצוני ל-Cassandra

  1. בתוך overrides.yaml, מוסיפים את ההגדרה הבאה כדי לאפשר שימוש בסודות חיצוניים ב-Cassandra:
    cassandra:
      auth:
        secretProviderClass: apigee-cassandra-auth-spc  # The name of the SecretProviderClass created in spc.yaml.

    cassandra.auth.secretProviderClass

  2. משתמשים ב-helm upgrade כדי להחיל את השינוי על הרכיבים apigee-operator ו-apigee-datastore:
    • בקר מאגר הנתונים ב-apigee-operator משתתף בהוצאה משימוש של Cassandra וברפליקציה של נתונים במהלך הרחבת האזור. כדי לבצע את המשימות האלה צריך את פרטי הכניסה של JMX ו-Jolokia.
      helm upgrade operator apigee-operator/ \
        --namespace $APIGEE_NAMESPACE> \
        --atomic \
        -f overrides.yaml
    • ‫apigee-datastore מספק פרטי כניסה שרכיבים במורד הזרם, כמו apigee-runtime, ‏Synchronizer ו-MART, משתמשים בהם כשהם מתחברים ל-Cassandra.
      helm upgrade datastore apigee-datastore/ \
        --namespace $APIGEE_NAMESPACE \
        --atomic \
        -f overrides.yaml
  3. לוודא שנעשה שימוש בסודות חיצוניים. כשהסודות החיצוניים מופעלים, נוספים Volume, Volume Mount ו-Environment Variable חדשים שמפנים לסודות.
    • מאמתים את הפריסה של apigee-controller-manager.

      מוודאים שקיים Volume בשם apigee-external-secrets שמפנה אל SecretProviderClass שנוצר למעלה:

      kubectl -n $APIGEE_NAMESPACE get deployment apigee-controller-manager -o jsonpath='{.spec.template.spec.volumes[?(@.name=="apigee-external-secrets")]}'

      פלט לדוגמה:

      {
        "csi": {
          "driver": "secrets-store.csi.k8s.io",
          "readOnly": true,
          "volumeAttributes": {
            "secretProviderClass": "apigee-cassandra-auth-spc"
          }
        },
        "name": "apigee-external-secrets"
      }

      בודקים אם קיים VolumeMount בשם apigee-external-secrets:

      kubectl -n $APIGEE_NAMESPACE get deployment apigee-controller-manager -o jsonpath='{.spec.template.spec.containers[?(@.name=="manager")].volumeMounts[?(@.name=="apigee-external-secrets")]}'

      פלט לדוגמה:

      {
        "mountPath": "/opt/apigee/externalsecrets",
        "name": "apigee-external-secrets",
        "readOnly": true
      }

      בודקים שקיימים Environment Variable שמפנים לסודות חיצוניים:

      kubectl -n $APIGEE_NAMESPACE get deployment apigee-controller-manager -o jsonpath='{.spec.template.spec.containers[?(@.name=="manager")].env}'

      פלט לדוגמה:

      [
        ...
        {
          "name": "CASSANDRA_JOLOKIA_USERNAME_PATH",
          "value": "/opt/apigee/externalsecrets/jolokiaUsername"
        },
        {
          "name": "CASSANDRA_JOLOKIA_PASSWORD_PATH",
          "value": "/opt/apigee/externalsecrets/jolokiaPassword"
        }
      ]

חזרה לגרסה קודמת של K8s Secret

  1. כדי לחזור לסודות לא חיצוניים, מסירים את ההגדרה secretProviderClass ב-overrides.yaml ומשתמשים בהגדרה הקודמת:
    cassandra:
          auth:
            secretProviderClass: apigee-cassandra-auth-spc # remove this line
  2. משתמשים ב-helm upgrade כדי להחיל את השינוי על הרכיבים apigee-operator ו-apigee-datastore:
    helm upgrade operator apigee-operator/ \
      --namespace $APIGEE_NAMESPACE \
      --atomic \
      -f overrides.yaml
    helm upgrade datastore apigee-datastore/ \
      --namespace $APIGEE_NAMESPACE \
      --atomic \
      -f overrides.yaml

פתרון בעיות: יצירת מאגר תגים של לקוח לצורך ניפוי באגים

אם אתם משתמשים ב-Vault, הקטע הזה מחליף את ההוראות בקטע פתרון הבעיות, יצירת מאגר לקוח לצורך ניפוי באגים.

בקטע הזה מוסבר איך ליצור קונטיינר לקוח שדרכו אפשר לגשת לכלי ניפוי באגים של Cassandra, כמו cqlsh. הכלים האלה מאפשרים לשלוח שאילתות לטבלאות של Cassandra, והם יכולים להיות שימושיים למטרות ניפוי באגים.

יצירת מאגר תגים בצד הלקוח

כדי ליצור את מאגר התגים בצד הלקוח, פועלים לפי השלבים הבאים:

  1. הקונטיינר משתמש באישור ה-TLS מה-Pod של apigee-cassandra-user-setup. בשלב הראשון צריך לאחזר את שם האישור:
    kubectl get secrets -n APIGEE_NAMESPACE --field-selector type=kubernetes.io/tls | grep apigee-cassandra-user-setup | awk '{print $1}'

    הפקודה הזו מחזירה את שם האישור. לדוגמה: apigee-cassandra-user-setup-rg-hybrid-b7d3b9c-tls.

  2. פותחים קובץ חדש ומדביקים בו את מפרט ה-pod הבא:
    apiVersion: v1
      kind: Pod
      metadata:
        labels:
        name: CASSANDRA_CLIENT_NAME   # For example: my-cassandra-client
        namespace: $APIGEE_NAMESPACE
      spec:
        containers:
        - name: CASSANDRA_CLIENT_NAME
          image: "gcr.io/apigee-release/hybrid/apigee-hybrid-cassandra-client:1.16.11"
          imagePullPolicy: Always
          command:
          - sleep
          - "3600"
          env:
          - name: CASSANDRA_SEEDS
            value: apigee-cassandra-default.apigee.svc.cluster.local
          - name: APIGEE_DML_USERNAME_PATH
            value: /opt/apigee/externalsecrets/dmlUsername
          - name: APIGEE_DML_PASSWORD_PATH
            value: /opt/apigee/externalsecrets/dmlPassword
          volumeMounts:
          - mountPath: /opt/apigee/ssl
            name: tls-volume
            readOnly: true
          - name: apigee-external-secrets
            mountPath: /opt/apigee/externalsecrets
            readOnly: true
        volumes:
        - name: tls-volume
          secret:
            defaultMode: 420
            secretName: apigee-cassandra-user-setup-vaibhavhybridor-8b3e61d-tls
        - name: apigee-external-secrets
          csi:
            driver: secrets-store.csi.k8s.io
            readOnly: true
            volumeAttributes:
              secretProviderClass: apigee-cass-password
        serviceAccount: apigee-cassandra-default
        serviceAccountName: apigee-cassandra-default
        restartPolicy: Never
  3. שומרים את הקובץ עם סיומת .yaml. לדוגמה: my-spec.yaml.
  4. מחילים את המפרט על האשכול:
    kubectl apply -f my-spec.yaml -n $APIGEE_NAMESPACE
  5. מתחברים למאגר:
    kubectl exec -n CASSANDRA_CLIENT_NAME -it -- bash
  6. מתחברים לממשק cqlsh של Cassandra באמצעות הפקודות הבאות. מזינים את הפקודות בדיוק כמו שהן מוצגות:
    APIGEE_DML_USER=$(cat "$APIGEE_DML_USERNAME_PATH")
    export APIGEE_DML_USER
    APIGEE_DML_PASSWORD=$(cat "$APIGEE_DML_PASSNAME_PATH")
    export APIGEE_DML_PASSWORD
    cqlsh ${CASSANDRA_SEEDS} -u ${APIGEE_DML_USER} -p ${APIGEE_DML_PASSWORD} --ssl

מחיקת ה-Pod של הלקוח

כדי למחוק את pod הלקוח של Cassandra, משתמשים בפקודה הבאה:

kubectl delete pods -n $APIGEE_NAMESPACE cassandra-client