בדף הזה מוסבר איך להגדיר שרת מרכזי ליומנים עבור מכשירי Google Distributed Cloud (GDC) במודל Air-gapped appliance דרך ארגון מרכז הנתונים של Google Distributed Cloud במודל Air-gapped.
כדי ליצור מיקום מרכזי לרישום ביומן, למכשיר GDC צריכים להיות הרכיבים הבאים בארגון מרכז הנתונים של GDC:
- פרויקט ייחודי
- קטגוריה ליומני הביקורת
- קטגוריה ביומן לפעולות
יצירת פרויקט
את השלבים הבאים צריך לבצע בארגון של מרכז הנתונים של GDC שאליו ייוצאו היומנים.
הגדרת
KUBECONFIGל-Org Management API:export KUBECONFIG=ORG_MANAGEMENT_API_KUBECONFIG_PATHכדי לקבל את ההרשאות שדרושות לייצוא יומנים, צריך לבקש מאדמין ה-IAM בארגון להקצות לכם את התפקיד ClusterRole Project Creator (
ClusterRole project-creator). מידע נוסף על התפקידים האלה זמין במאמר הכנת הרשאות IAM.מחילים את המשאב המותאם אישית של הפרויקט כדי ליצור פרויקט ייחודי למכשיר GDC שממנו ייוצאו היומנים:
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בודקים אם הפרויקט החדש זמין במכשיר GDC:
kubectl get namespace APPLIANCE_PROJECT_NAMEמקשרים את הפרויקט החדש לחשבון לחיוב. כדי לעקוב אחרי עלויות המשאבים בפרויקט, צריך שיהיה לכם חשבון לחיוב שמקושר לפרויקט.
כדי לקבל את ההרשאות שנדרשות לייצוא יומנים, צריך לבקש מאדמין ה-IAM בארגון להקצות לכם את תפקיד אדמין ה-IAM בפרויקט (
project-iam-admin) במרחב השמותAPPLIANCE_PROJECT_NAME.
יצירת קטגוריה
את השלבים הבאים צריך לבצע מנהל הפלטפורמה (PA) בארגון של מרכז הנתונים של GDC שאליו ייוצאו היומנים.
הגדרת
KUBECONFIGל-Org Management API:export KUBECONFIG=ORG_MANAGEMENT_API_KUBECONFIG_PATHכדי לקבל את ההרשאות שנדרשות לייצוא יומנים, צריך לבקש מאדמין ה-IAM בארגון להקצות לכם את התפקיד 'אדמין של קטגוריית פרויקט' (
project-bucket-admin) במרחב השמותAPPLIANCE_PROJECT_NAME.מחילים את המשאב המותאם אישית של הקטגוריה כדי ליצור קטגוריה:
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אחרי שיוצרים את ה-bucket, מריצים את הפקודה הבאה כדי לאשר ולבדוק את הפרטים של ה-bucket:
kubectl describe buckets BUCKET_NAME -n APPLIANCE_PROJECT_NAMEיוצרים
ProjectServiceAccountכדי לגשת לאובייקטים בקטגוריה.kubectl apply -f - <<EOF --- apiVersion: resourcemanager.gdc.goog/v1 kind: ProjectServiceAccount metadata: name: BUCKET_NAME-read-write-sa namespace: APPLIANCE_PROJECT_NAME spec: {} EOFמוודאים שה-
ProjectServiceAccountמועבר:kubectl get projectserviceaccount BUCKET_NAME-read-write-sa -n APPLIANCE_PROJECT_NAME -o json | jq '.status'מוודאים שההרשאות
readו-writeשלServiceAccountנוספו לקטגוריה.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מקבלים את הסוד שמכיל את פרטי הכניסה לקטגוריה:
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'הפלט צריך להיראות כמו בדוגמה הבאה, שבה מוצג שם הסוד של הקטגוריה:
"object-storage-key-sysstd-sa-olxv4dnwrwul4bshu37ikebgovrnvl773owaw3arx225rfi56swa"ייצוא הערך למשתנה:
export BUCKET_RW_SECRET_NAME=BUCKET_RW_SECRET_NAMEמקבלים את מזהה המפתח לגישה לקטגוריה:
kubectl get secret $BUCKET_RW_SECRET_NAME -n appliance-xyz -o json | jq -r '.data."access-key-id"' | base64 -diהפלט צריך להיראות כמו בדוגמה הבאה:
PCEW2HU47Y8ACUWQO4SKמקבלים את מפתח הגישה הסודי לקטגוריה:
kubectl get secret $BUCKET_RW_SECRET_NAME -n appliance-xyz -o json | jq -r '.data."secret-access-key"' | base64 -diהפלט צריך להיראות כמו בדוגמה הבאה:
TzGdAbgp4h2i5UeiYa9k09rNPFQ2tkYADs67+65Eמקבלים את נקודת הקצה של ה-bucket:
kubectl get bucket BUCKET_NAME -n APPLIANCE_PROJECT_NAME -o json | jq '.status.endpoint'הפלט צריך להיראות כמו בדוגמה הבאה:
https://objectstorage.org-1.zone1.google.gdch.testמקבלים את השם המוגדר במלואו של הקטגוריה:
kubectl get bucket BUCKET_NAME -n APPLIANCE_PROJECT_NAME -o json | jq '.status.fullyQualifiedName'הפלט צריך להיראות כמו בדוגמה הבאה:
aaaoa9a-logs-bucket
העברת נתונים מ-GDC
כדי להעביר יומנים ממכשיר GDC לקטגוריה שנוצרה קודם לכן במרכז הנתונים של GDC עם air gap, פועלים לפי ההוראות שבמאמר ייצוא יומנים לקטגוריה מרוחקת. צריך להשתמש בנקודת הקצה של הקטגוריה, בשם המלא, במזהה מפתח הגישה ובמפתח הגישה הסודי.
הגדרת Loki ו-Grafana ב-Google Distributed Cloud במודל Air-gapped
את השלבים הבאים צריך לבצע מפעיל התשתית (IO) בארגון של מרכז הנתונים עם GDC עם air gap שאליו יובאו היומנים.
קבלת תפקידי IAM
כדי לקבל את ההרשאות שדרושות לייצוא יומנים, צריך לבקש מאדמין ה-IAM בארגון להקצות לכם את התפקיד Logs Restore Admin (אדמין לשחזור יומנים) (logs-restore-admin) במרחב השמות obs-system באשכול התשתית, ואת התפקידים Datasource Viewer (צפייה במקור נתונים) (datasource-viewer) ו-Datasource Editor (עריכה של מקור נתונים) (datasource-editor) במרחב השמות obs-system במישור הניהול.
הגדרת Loki
מגדירים את
KUBECONFIGלאשכול Org Infra:export KUBECONFIG=ORG_INFRA_CLUSTER_KUBECONFIG_PATHמקבלים את המזהה של מפתח הגישה ואת מפתח הגישה הסודי של קטגוריית היומנים של מכשיר ה-PA מ-PA ויוצרים Secret שמכיל את פרטי הכניסה במרחב השמות
obs-system: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מקבלים את נקודת הקצה ואת השם המוגדר במלואו של קטגוריית יומני הרישום של מכשיר ה-PA ויוצרים 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יוצרים שירות ו-Loki
statefulset: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
הגדרת
KUBECONFIGל-Org Management API:export KUBECONFIG=ORG_MANAGEMENT_API_KUBECONFIG_PATHיוצרים
DataSourcesליומני התשתית והפלטפורמה: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
הצגת יומנים ב-Grafana של מרכז נתונים במודל Air-gapped ב-Google Distributed Cloud
אפשר לראות את היומנים שמיוצאים לקטגוריה של Google Distributed Cloud במודל Air-gapped במופע Grafana של פרויקט מכשיר GDC.