Server für zentralisierte Logs einrichten

Auf dieser Seite wird beschrieben, wie Sie einen zentralen Logserver für Google Distributed Cloud-Geräte (GDC) in einer Air-Gap-Umgebung über die Google Distributed Cloud-Organisation für Air-Gap-Rechenzentren einrichten.

Damit ein zentraler Speicherort für Logs erstellt werden kann, muss die GDC-Appliance die folgenden Komponenten in der GDC-Rechenzentrumsorganisation haben:

  • einzigartiges Projekt
  • Bucket für die Audit-Logs
  • Bucket für Betriebslogs

Projekt erstellen

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

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

    export KUBECONFIG=ORG_MANAGEMENT_API_KUBECONFIG_PATH
    
  2. Bitten Sie Ihren IAM-Administrator der 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. Damit Sie die Kosten für Projektressourcen nachverfolgen können, muss Ihrem Projekt ein Rechnungskonto zugewiesen sein.

  6. Bitten Sie Ihren IAM-Administrator der Organisation, Ihnen die Rolle „IAM-Administrator des Projekts“ (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 (Platform Administrator, PA) in der GDC-Rechenzentrumsorganisation ausgeführt werden, in die die Protokolle exportiert werden.

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

    export KUBECONFIG=ORG_MANAGEMENT_API_KUBECONFIG_PATH
    
  2. Bitten Sie Ihren IAM-Administrator der 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 den Bucket zu bestätigen und seine Details 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 ProjectServiceAccount weitergegeben wird:

    kubectl get projectserviceaccount BUCKET_NAME-read-write-sa -n APPLIANCE_PROJECT_NAME -o json | jq '.status'
    
  7. Prüfen Sie, ob der 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 Anmeldedaten für den Zugriff auf 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 Bucket zu übertragen, der zuvor im GDC-Air-Gap-Rechenzentrum erstellt wurde. Verwenden Sie dazu den Endpunkt des Buckets, den voll qualifizierten Namen, die Zugriffsschlüssel-ID und den geheimen Zugriffsschlüssel.

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

Die folgenden Schritte müssen vom Infrastrukturoperator (IO) in der GDC-Organisation des Air-Gap-Rechenzentrums ausgeführt werden, in das die Protokolle exportiert wurden.

IAM-Rollen abrufen

Bitten Sie Ihren IAM-Administrator der 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 Managementebene zuzuweisen, damit Sie die Berechtigungen zum Exportieren von Logs erhalten.

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 Appliance-Logs-Bucket 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 Appliance-Logs-Buckets vom PA ab und erstellen Sie einen 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 einen Loki-statefulset und -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 einrichten DataSource

  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 Google Distributed Cloud mit Air Gap-Rechenzentrum ansehen

Die in den Google Distributed Cloud-Bucket für das Air-Gap-Rechenzentrum exportierten Logs können in der Grafana-Instanz des GDC-Geräteprojekts aufgerufen werden.