Server für zentralisierte Logs einrichten

Mit einem zentralen Logserver können Sie Logs von GDC-Appliances (Google Distributed Cloud) mit Air Gap an einem einzigen Ort über eine GDC-Rechenzentrumsorganisation mit Air Gap aggregieren, speichern und abfragen.

Zum Einrichten dieser zentralen Logging-Umgebung erstellen Sie ein dediziertes Projekt und separate Ziel-Buckets für Audit- und Betriebslogs in der Rechenzentrumsorganisation. Nachdem Sie Logs von der GDC-Appliance in diese Buckets exportiert haben, konfigurieren Sie Loki- und Grafana-Datenquellen in der Rechenzentrumsorganisation, um die exportierten Logs aufzurufen.

Projekt erstellen

Die folgenden Schritte müssen in der GDC-Rechenzentrumsorganisation ausgeführt werden, in die die Logs exportiert werden.

  1. Legen Sie KUBECONFIG auf die Org Management API fest:

    export KUBECONFIG=ORG_MANAGEMENT_API_KUBECONFIG_PATH
    
  2. Bitten Sie den IAM-Administrator Ihrer Organisation, Ihnen die ClusterRole „Project Creator“ (ClusterRole project-creator) zuzuweisen, um die Berechtigungen zu erhalten, die Sie zum Exportieren von Logs benötigen. Weitere Informationen zu diesen Rollen finden Sie unter IAM-Berechtigungen vorbereiten.

  3. Wenden Sie die benutzerdefinierte Projektressource an, um ein eindeutiges Projekt für die GDC-Appliance zu erstellen, aus der die Logs exportiert werden:

    kubectl apply -f - <<EOF
    apiVersion: resourcemanager.gdc.goog/v1
    kind: Project
    metadata:
      namespace: platform
      name: APPLIANCE_PROJECT_NAME
      labels:                                                                                                                                                                                                                                                                   
        object.gdc.goog/tenant-category: user                                                                                                                                   
    EOF
    
  4. Prüfen Sie, ob das neue Projekt in der GDC-Appliance verfügbar ist:

    kubectl get namespace APPLIANCE_PROJECT_NAME
    
  5. Verknüpfen Sie Ihr neues Projekt mit einem Rechnungskonto. Wenn Sie die Kosten für Projektressourcen im Blick behalten möchten, müssen Sie ein Rechnungskonto mit Ihrem Projekt verknüpfen.

  6. Bitten Sie den IAM-Administrator Ihrer Organisation, Ihnen die Rolle „Project IAM Admin“ (project-iam-admin) im Namespace APPLIANCE_PROJECT_NAME zuzuweisen, um die Berechtigungen zu erhalten, die Sie zum Exportieren von Logs benötigen.

Bucket erstellen

Die folgenden Schritte müssen vom Plattformadministrator (PA) in der GDC-Rechenzentrumsorganisation ausgeführt werden, in die die Logs exportiert werden.

  1. Legen Sie KUBECONFIG auf die Org Management API fest:

    export KUBECONFIG=ORG_MANAGEMENT_API_KUBECONFIG_PATH
    
  2. Bitten Sie den IAM-Administrator Ihrer Organisation, Ihnen die Rolle „Project Bucket Admin“ (project-bucket-admin) im Namespace APPLIANCE_PROJECT_NAME zuzuweisen, um die Berechtigungen zu erhalten, die Sie zum Exportieren von Logs benötigen.

  3. Wenden Sie die benutzerdefinierte Bucket-Ressource an, um einen Bucket zu erstellen:

    apiVersion: object.gdc.goog/v1
    kind: Bucket
    metadata:
      name: BUCKET_NAME
      namespace: APPLIANCE_PROJECT_NAME
      labels:                                                                                                                                                                     
        object.gdc.goog/bucket-type: normal                                                                                                                                       
        object.gdc.goog/encryption-version: v2                                                                                                                                    
        object.gdc.goog/tenant-category: user
    spec:                                                                                                                                                                         
      description: Bucket for storing appliance xyz audit logs                                                                                                                     
      location: zone1                                                                                                                                                             
      storageClass: Standard
    
  4. Führen Sie nach dem Erstellen des Buckets den folgenden Befehl aus, um die Details des Buckets zu bestätigen und zu prüfen:

    kubectl describe buckets BUCKET_NAME -n APPLIANCE_PROJECT_NAME
    
  5. Erstellen Sie ein ProjectServiceAccount für den Zugriff auf Objekte im Bucket.

    kubectl apply -f - <<EOF
    ---
    apiVersion: resourcemanager.gdc.goog/v1
    kind: ProjectServiceAccount
    metadata:
      name: BUCKET_NAME-read-write-sa
      namespace: APPLIANCE_PROJECT_NAME
    spec: {}
    EOF
    
  6. Prüfen Sie, ob die ProjectServiceAccount weitergegeben wurde:

    kubectl get projectserviceaccount BUCKET_NAME-read-write-sa -n APPLIANCE_PROJECT_NAME -o json | jq '.status'
    
  7. Achten Sie darauf, dass das ServiceAccount die Berechtigungen read und write für den Bucket hat.

    kubectl apply -f - <<EOF
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: BUCKET_NAME-read-write-role
      namespace: APPLIANCE_PROJECT_NAME
    rules:
    - apiGroups:
      - object.gdc.goog
      resourceNames:
      - BUCKET_NAME
      resources:
      - buckets
      verbs:
      - read-object
      - write-object
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: BUCKET_NAME-read-write-rolebinding
      namespace: APPLIANCE_PROJECT_NAME
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: BUCKET_NAME-read-write-role
    subjects:
    - kind: ServiceAccount
      name: BUCKET_NAME-read-write-sa
      namespace: APPLIANCE_PROJECT_NAME
    EOF
    
  8. Rufen Sie das Secret ab, das die Zugriffsdaten für den Bucket enthält:

    kubectl get secret -n APPLIANCE_PROJECT_NAME -o json| jq --arg jq_src BUCKET_NAME-read-write-sa '.items[].metadata|select(.annotations."object.gdc.goog/subject"==$jq_src)|.name'
    

    Die Ausgabe muss wie im folgenden Beispiel aussehen, in dem der Secret-Name des Buckets angezeigt wird:

    "object-storage-key-sysstd-sa-olxv4dnwrwul4bshu37ikebgovrnvl773owaw3arx225rfi56swa"
    
  9. Exportieren Sie den Wert in eine Variable:

    export BUCKET_RW_SECRET_NAME=BUCKET_RW_SECRET_NAME
    
  10. Rufen Sie die Schlüssel-ID für den Bucket-Zugriff ab:

    kubectl get secret $BUCKET_RW_SECRET_NAME -n appliance-xyz -o json | jq -r '.data."access-key-id"' | base64 -di
    

    Die Ausgabe muss wie im folgenden Beispiel aussehen:

    PCEW2HU47Y8ACUWQO4SK
    
  11. Rufen Sie den geheimen Zugriffsschlüssel für den Bucket ab:

    kubectl get secret $BUCKET_RW_SECRET_NAME -n appliance-xyz -o json | jq -r '.data."secret-access-key"' | base64 -di
    

    Die Ausgabe muss wie im folgenden Beispiel aussehen:

    TzGdAbgp4h2i5UeiYa9k09rNPFQ2tkYADs67+65E
    
  12. Rufen Sie den Endpunkt des Buckets ab:

    kubectl get bucket BUCKET_NAME -n APPLIANCE_PROJECT_NAME -o json | jq '.status.endpoint'
    

    Die Ausgabe muss wie im folgenden Beispiel aussehen:

    https://objectstorage.org-1.zone1.google.gdch.test
    
  13. Rufen Sie den vollständig qualifizierten Namen des Buckets ab:

    kubectl get bucket BUCKET_NAME -n APPLIANCE_PROJECT_NAME -o json | jq '.status.fullyQualifiedName'
    

    Die Ausgabe muss wie im folgenden Beispiel aussehen:

    aaaoa9a-logs-bucket
    

Daten aus GDC übertragen

Folgen Sie der Anleitung unter Logs in einen Remote-Bucket exportieren, um Logs von der GDC-Appliance in den zuvor im GDC-Rechenzentrum mit Air Gap erstellten Bucket zu übertragen. Verwenden Sie dazu den Endpunkt des Buckets, den vollständig qualifizierten Namen, die Zugriffsschlüssel-ID und den geheimen Zugriffsschlüssel.

Loki und Grafana im Google Distributed Cloud-Rechenzentrum mit Air Gap einrichten

Die folgenden Schritte müssen vom Infrastrukturbetreiber (Infrastructure Operator, IO) in der GDC-Organisation mit Air Gap ausgeführt werden, in die die Logs exportiert wurden.

IAM-Rollen abrufen

Bitten Sie den IAM-Administrator Ihrer Organisation, Ihnen die Rolle „Logs Restore Admin“ (logs-restore-admin) im Namespace obs-system im Infrastrukturcluster und die Rollen „Datasource Viewer“ (datasource-viewer) und „Datasource Editor“ (datasource-editor) im Namespace obs-system in der Verwaltungsebene zuzuweisen, um die Berechtigungen zu erhalten, die Sie zum Exportieren von Logs benötigen.

Loki einrichten

  1. Legen Sie KUBECONFIG auf den Org Infra-Cluster fest:

    export KUBECONFIG=ORG_INFRA_CLUSTER_KUBECONFIG_PATH
    
  2. Rufen Sie die Zugriffsschlüssel-ID und den geheimen Zugriffsschlüssel für den Bucket mit den Appliance-Logs vom PA ab und erstellen Sie ein Secret, das die Anmeldedaten im Namespace obs-system enthält:

    kubectl create secret generic -n obs-system APPLIANCE_LOGS_BUCKET_SECRET_NAME 
    --from-literal=access-key-id=APPLIANCE_LOGS_BUCKET_ACCESS_KEY_ID 
    --from-literal=secret-access-key=APPLIANCE_LOGS_BUCKET_SECRET_ACCESS_KEY
    
  3. Rufen Sie den Endpunkt und den vollständig qualifizierten Namen des Buckets für Appliance-Logs vom PA ab und erstellen Sie eine Loki-configmap:

    kubectl apply -f - <<EOF
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: CONFIGMAP_NAME
      namespace: obs-system
    data:
      loki.yaml: |-
        auth_enabled: true
        common:
          ring:
            kvstore:
              store: inmemory
        compactor:
          working_directory: /data/loki/compactor
          compaction_interval: 10m
          retention_enabled: true
          retention_delete_delay: 2h
          retention_delete_worker_count: 150
          delete_request_store: s3
        ingester:
          chunk_target_size: 1572864
          chunk_encoding: snappy
          max_chunk_age: 2h
          chunk_idle_period: 90m
          chunk_retain_period: 30s
          autoforget_unhealthy: true
          lifecycler:
            ring:
              kvstore:
                store: inmemory
              replication_factor: 1
              heartbeat_timeout: 10m
          wal:
            enabled: false
        limits_config:
          discover_service_name: []
          retention_period: 48h
          reject_old_samples: false
          ingestion_rate_mb: 256
          ingestion_burst_size_mb: 256
          max_streams_per_user: 20000
          max_global_streams_per_user: 20000
          max_line_size: 0
          per_stream_rate_limit: 256MB
          per_stream_rate_limit_burst: 256MB
          shard_streams:
            enabled: false
            desired_rate: 3MB
        schema_config:
          configs:
          - from: "2020-10-24"
            index:
              period: 24h
              prefix: index_
            object_store: s3
            schema: v13
            store: tsdb
        server:
          http_listen_port: 3100
          grpc_server_max_recv_msg_size: 104857600
          grpc_server_max_send_msg_size: 104857600
          graceful_shutdown_timeout: 60s
        analytics:
          reporting_enabled: false
        storage_config:
          tsdb_shipper:
            active_index_directory: /tsdb/index
            cache_location: /tsdb/index-cache
            cache_ttl: 24h
          aws:
            endpoint: APPLIANCE_LOGS_BUCKET_ENDPOINT
            bucketnames: APPLIANCE_LOGS_BUCKET_FULLY_QUALIFIED_NAME
            access_key_id: ${S3_ACCESS_KEY_ID}
            secret_access_key: ${S3_SECRET_ACCESS_KEY}
            s3forcepathstyle: true
    ---
    EOF
    
  4. Erstellen Sie ein Loki-statefulset und einen Loki-Dienst:

    kubectl apply -f - <<EOF
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      labels:
        app: STATEFULSET_NAME
      name: STATEFULSET_NAME
      namespace: obs-system
    spec:
      persistentVolumeClaimRetentionPolicy:
        whenDeleted: Retain
        whenScaled: Retain
      podManagementPolicy: OrderedReady
      replicas: 1
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: STATEFULSET_NAME
      serviceName: STATEFULSET_NAME
      template:
        metadata:
          labels:
            app: STATEFULSET_NAME
            istio.io/rev: default
        spec:
          affinity:
            nodeAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
              - preference:
                  matchExpressions:
                  - key: node-role.kubernetes.io/control-plane
                    operator: DoesNotExist
                  - key: node-role.kubernetes.io/master
                    operator: DoesNotExist
                weight: 1
            podAntiAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
              - podAffinityTerm:
                  labelSelector:
                    matchExpressions:
                    - key: app
                      operator: In
                      values:
                      - STATEFULSET_NAME
                  topologyKey: kubernetes.io/hostname
                weight: 100
          containers:
          - args:
            - -config.file=/etc/loki/loki.yaml
            - -config.expand-env=true
            - -target=all
            env:
            - name: S3_ACCESS_KEY_ID
              valueFrom:
                secretKeyRef:
                  key: access-key-ID
                  name: APPLIANCE_LOGS_BUCKET_SECRET_NAME
                  optional: false
            - name: S3_SECRET_ACCESS_KEY
              valueFrom:
                  secretKeyRef:
                    key: secret-access-key
                    name: APPLIANCE_LOGS_BUCKET_SECRET_NAME
                    optional: false
            image: gcr.io/private-cloud-staging/loki:v3.0.1-gke.1
            imagePullPolicy: Always
            livenessProbe:
              failureThreshold: 3
              httpGet:
                path: /ready
                port: loki-server
                scheme: HTTP
              initialDelaySeconds: 330
              periodSeconds: 10
              successThreshold: 1
              timeoutSeconds: 1
            name: STATEFULSET_NAME
            ports:
            - containerPort: 3100
              name: loki-server
              protocol: TCP
            - containerPort: 7946
              name: gossip-ring
              protocol: TCP
            readinessProbe:
              failureThreshold: 3
              httpGet:
                path: /ready
                port: loki-server
                scheme: HTTP
              initialDelaySeconds: 45
              periodSeconds: 10
              successThreshold: 1
              timeoutSeconds: 1
            resources:
              limits:
                ephemeral-storage: 2000Mi
                memory: 8000Mi
              requests:
                cpu: 300m
                ephemeral-storage: 2000Mi
                memory: 1000Mi
            securityContext:
              readOnlyRootFilesystem: true
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
            volumeMounts:
            - mountPath: /etc/loki
              name: config
            - mountPath: /data
              name: loki-storage
            - mountPath: /tsdb
              name: loki-tsdb-storage
            - mountPath: /tmp
              name: temp
            - mountPath: /tmp/loki/rules-temp
              name: tmprulepath
            - mountPath: /etc/ssl/certs
              name: trust-bundle
              readOnly: true
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext:
            fsGroup: 10001
            runAsGroup: 10001
            runAsUser: 10001
          terminationGracePeriodSeconds: 4800
          volumes:
          - emptyDir: {}
            name: temp
          - emptyDir: {}
            name: tmprulepath
          - configMap:
              defaultMode: 420
              name: trust-store-root-ext
              optional: true
            name: trust-bundle
          - configMap:
              defaultMode: 420
              name: CONFIGMAP_NAME
            name: config
      updateStrategy:
        type: RollingUpdate
      volumeClaimTemplates:
      - apiVersion: v1
        kind: PersistentVolumeClaim
        metadata:
          creationTimestamp: null
          name: loki-storage
        spec:
          accessModes:
          - ReadWriteOnce
          resources:
            requests:
              storage: 5Gi
          storageClassName: standard-rwo
          volumeMode: Filesystem
      - apiVersion: v1
        kind: PersistentVolumeClaim
        metadata:
          creationTimestamp: null
          name: loki-tsdb-storage
        spec:
          accessModes:
          - ReadWriteOnce
          resources:
            requests:
              storage: 5Gi
          storageClassName: standard-rwo
          volumeMode: Filesystem
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: STATEFULSET_NAME
      namespace: obs-system
    spec:
      internalTrafficPolicy: Cluster
      ipFamilies:
      - IPv4
      ipFamilyPolicy: SingleStack
      ports:
      - name: loki-server
        port: 3100
        protocol: TCP
        targetPort: loki-server
      selector:
        app: STATEFULSET_NAME
      sessionAffinity: None
      type: ClusterIP
    ---
    EOF
    

Grafana DataSource einrichten

  1. Legen Sie KUBECONFIG auf die Org Management API fest:

    export KUBECONFIG=ORG_MANAGEMENT_API_KUBECONFIG_PATH
    
  2. Erstellen Sie DataSources für die Infrastruktur- und Plattformlogs:

    kubectl apply -f - <<EOF
    ---
    apiVersion: monitoring.private.gdc.goog/v1alpha1
    kind: Datasource
    metadata:
      name: INFRA_DATASOURCE_NAME
      namespace: APPLIANCE_PROJECT_NAME-obs-system
    spec:
      datasource:
        access: proxy
        isDefault: false
        jsonData:
          httpHeaderName1: X-Scope-OrgID
        name: UI_FRIENDLY_NAME
        orgId: 1
        readOnly: true
        secureJsonData:
          httpHeaderValue1: infra-obs
        type: loki
        uid: INFRA_DATASOURCE_NAME
        url: http://STATEFULSET_NAME.obs-system.svc:3100
        version: 1
        withCredentials: false
    ---
    apiVersion: monitoring.private.gdc.goog/v1alpha1
    kind: Datasource
    metadata:
      name: PLATFORM_DATASOURCE_NAME
      namespace: APPLIANCE_PROJECT_NAME-obs-system
    spec:
      datasource:
        access: proxy
        isDefault: false
        jsonData:
          httpHeaderName1: X-Scope-OrgID
        name: UI_FRIENDLY_NAME
        orgId: 1
        readOnly: true
        secureJsonData:
          httpHeaderValue1: platform-obs
        type: loki
        uid: PLATFORM_DATASOURCE_NAME
        url: http://STATEFULSET_NAME.obs-system.svc:3100
        version: 1
        withCredentials: false
    ---
    EOF
    

Logs in Grafana im Rechenzentrum von Google Distributed Cloud mit Air Gap ansehen

Die in den Bucket des Air-Gap-Rechenzentrums von Google Distributed Cloud exportierten Logs können in der Grafana-Instanz des GDC-Appliance-Projekts angezeigt werden.