diff --git a/.sops.yaml b/.sops.yaml index 87b509914b..826c010aa2 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -1,5 +1,7 @@ creation_rules: - path_regex: .*/secrets/.* gcp_kms: projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs + - path_regex: .*/kops/ssh-keys/.* + gcp_kms: projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs - path_regex: config/secrets.yaml$ gcp_kms: projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs \ No newline at end of file diff --git a/config/hubs/carbonplan.cluster.yaml b/config/hubs/carbonplan.cluster.yaml new file mode 100644 index 0000000000..66972b88e3 --- /dev/null +++ b/config/hubs/carbonplan.cluster.yaml @@ -0,0 +1,182 @@ +name: carbonplan +provider: kubeconfig +kubeconfig: + file: secrets/carbonplan.yaml +hubs: + - name: staging + domain: staging.carbonplan.2i2c.cloud + template: daskhub + auth0: + connection: github + config: &carbonPlanHubConfig + scratchBucket: + enabled: false + basehub: + nfsPVC: + nfs: + # from https://docs.aws.amazon.com/efs/latest/ug/mounting-fs-nfs-mount-settings.html + mountOptions: + - rsize=1048576 + - wsize=1048576 + - timeo=600 + - soft # We pick soft over hard, so NFS lockups don't lead to hung processes + - retrans=2 + - noresvport + serverIP: fs-8a4e4f8d.efs.us-west-2.amazonaws.com + baseShareName: / + shareCreator: + tolerations: + - key: node-role.kubernetes.io/master + operator: "Exists" + effect: "NoSchedule" + jupyterhub: + homepage: + templateVars: + org: + name: Carbon Plan + logo_url: https://pbs.twimg.com/profile_images/1262387945971101697/5q_X3Ruk_400x400.jpg + url: https://carbonplan.org + designed_by: + name: 2i2c + url: https://2i2c.org + operated_by: + name: 2i2c + url: https://2i2c.org + funded_by: + name: Carbon Plan + url: https://carbonplan.org + singleuser: + initContainers: + # Need to explicitly fix ownership here, since EFS doesn't do anonuid + - name: volume-mount-ownership-fix + image: busybox + command: ["sh", "-c", "id && chown 1000:1000 /home/jovyan && ls -lhd /home/jovyan"] + securityContext: + runAsUser: 0 + volumeMounts: + - name: home + mountPath: /home/jovyan + subPath: "{username}" + image: + name: carbonplan/trace-python-notebook + tag: sha-da2d1c9 + profileList: + # The mem-guarantees are here so k8s doesn't schedule other pods + # on these nodes. + - display_name: "Small: r5.large" + description: "~2 CPU, ~15G RAM" + kubespawner_override: + # Expllicitly unset mem_limit, so it overrides the default memory limit we set in + # basehub/values.yaml + mem_limit: null + mem_guarantee: 12G + node_selector: + node.kubernetes.io/instance-type: r5.large + - display_name: "Medium: r5.xlarge" + description: "~4 CPU, ~30G RAM" + kubespawner_override: + mem_limit: null + mem_guarantee: 29G + node_selector: + node.kubernetes.io/instance-type: r5.xlarge + - display_name: "Large: r5.2xlarge" + description: "~8 CPU, ~60G RAM" + kubespawner_override: + mem_limit: null + mem_guarantee: 60G + node_selector: + node.kubernetes.io/instance-type: r5.2xlarge + - display_name: "Huge: r5.8xlarge" + description: "~32 CPU, ~256G RAM" + kubespawner_override: + mem_limit: null + mem_guarantee: 250G + node_selector: + node.kubernetes.io/instance-type: r5.8xlarge + scheduling: + userPlaceholder: + enabled: false + replicas: 0 + userScheduler: + enabled: false + proxy: + service: + type: LoadBalancer + https: + enabled: true + chp: + nodeSelector: {} + tolerations: + - key: "node-role.kubernetes.io/master" + effect: "NoSchedule" + traefik: + nodeSelector: {} + tolerations: + - key: "node-role.kubernetes.io/master" + effect: "NoSchedule" + hub: + allowNamedServers: true + networkPolicy: + # FIXME: For dask gateway + enabled: false + readinessProbe: + enabled: false + nodeSelector: {} + tolerations: + - key: "node-role.kubernetes.io/master" + effect: "NoSchedule" + dask-gateway: + traefik: + tolerations: + - key: "node-role.kubernetes.io/master" + effect: "NoSchedule" + controller: + tolerations: + - key: "node-role.kubernetes.io/master" + effect: "NoSchedule" + gateway: + tolerations: + - key: "node-role.kubernetes.io/master" + effect: "NoSchedule" + # TODO: figure out a replacement for userLimits. + extraConfig: + optionHandler: | + from dask_gateway_server.options import Options, Integer, Float, String + def cluster_options(user): + def option_handler(options): + if ":" not in options.image: + raise ValueError("When specifying an image you must also provide a tag") + extra_annotations = { + "hub.jupyter.org/username": user.name, + "prometheus.io/scrape": "true", + "prometheus.io/port": "8787", + } + extra_labels = { + "hub.jupyter.org/username": user.name, + } + return { + "worker_cores_limit": options.worker_cores, + "worker_cores": min(options.worker_cores / 2, 1), + "worker_memory": "%fG" % options.worker_memory, + "image": options.image, + "scheduler_extra_pod_annotations": extra_annotations, + "worker_extra_pod_annotations": extra_annotations, + "scheduler_extra_pod_labels": extra_labels, + "worker_extra_pod_labels": extra_labels, + } + return Options( + Integer("worker_cores", 2, min=1, max=16, label="Worker Cores"), + Float("worker_memory", 4, min=1, max=32, label="Worker Memory (GiB)"), + String("image", default="pangeo/pangeo-notebook:latest", label="Image"), + handler=option_handler, + ) + c.Backend.cluster_options = cluster_options + idle: | + # timeout after 30 minutes of inactivity + c.KubeClusterConfig.idle_timeout = 1800 + - name: prod + domain: carbonplan.2i2c.cloud + template: daskhub + auth0: + connection: github + config: *carbonPlanHubConfig \ No newline at end of file diff --git a/hub-templates/basehub/values.yaml b/hub-templates/basehub/values.yaml index bda8c5768c..92095cc2b1 100644 --- a/hub-templates/basehub/values.yaml +++ b/hub-templates/basehub/values.yaml @@ -52,7 +52,7 @@ jupyterhub: userScheduler: enabled: true nodeSelector: - hub.jupyter.org/pool-name: core-pool + hub.jupyter.org/node-purpose: core resources: requests: # FIXME: Just unset this? @@ -72,7 +72,7 @@ jupyterhub: type: ClusterIP chp: nodeSelector: - hub.jupyter.org/pool-name: core-pool + hub.jupyter.org/node-purpose: core resources: requests: # FIXME: We want no guarantees here!!! @@ -83,7 +83,7 @@ jupyterhub: memory: 1Gi traefik: nodeSelector: - hub.jupyter.org/pool-name: core-pool + hub.jupyter.org/node-purpose: core resources: requests: memory: 64Mi @@ -102,7 +102,7 @@ jupyterhub: startTimeout: 600 # 10 mins, because sometimes we have too many new nodes coming up together defaultUrl: /tree nodeSelector: - hub.jupyter.org/pool-name: user-pool + hub.jupyter.org/node-purpose: user image: name: set_automatically_by_automation tag: 1b83c4f @@ -183,7 +183,7 @@ jupyterhub: JupyterHub: authenticator_class: oauthenticator.generic.GenericOAuthenticator nodeSelector: - hub.jupyter.org/pool-name: core-pool + hub.jupyter.org/node-purpose: core networkPolicy: enabled: true ingress: diff --git a/hub-templates/daskhub/values.yaml b/hub-templates/daskhub/values.yaml index cef9db1a81..483648c820 100644 --- a/hub-templates/daskhub/values.yaml +++ b/hub-templates/daskhub/values.yaml @@ -123,10 +123,10 @@ dask-gateway: # See https://github.com/dask/dask-gateway/blob/master/resources/helm/dask-gateway/values.yaml controller: nodeSelector: - hub.jupyter.org/pool-name: core-pool + k8s.dask.org/node-purpose: core gateway: nodeSelector: - hub.jupyter.org/pool-name: core-pool + k8s.dask.org/node-purpose: core backend: scheduler: extraPodConfig: @@ -143,8 +143,7 @@ dask-gateway: value: "user" effect: "NoSchedule" nodeSelector: - # Schedulers should be in the user pool - hub.jupyter.org/pool-name: user-pool + k8s.dask.org/node-purpose: scheduler cores: request: 0.01 limit: 1 @@ -171,7 +170,7 @@ dask-gateway: effect: "NoSchedule" nodeSelector: # Dask workers get their own pre-emptible pool - hub.jupyter.org/pool-name: dask-worker-pool + k8s.dask.org/node-purpose: worker # TODO: figure out a replacement for userLimits. extraConfig: @@ -217,6 +216,6 @@ dask-gateway: type: jupyterhub # Use JupyterHub to authenticate with Dask Gateway traefik: nodeSelector: - hub.jupyter.org/pool-name: core-pool + k8s.dask.org/node-purpose: core service: type: ClusterIP # Access Dask Gateway through JupyterHub. To access the Gateway from outside JupyterHub, this must be changed to a `LoadBalancer`. diff --git a/kops/carbonplan.jsonnet b/kops/carbonplan.jsonnet index c266c3fe38..6f6e30bac8 100644 --- a/kops/carbonplan.jsonnet +++ b/kops/carbonplan.jsonnet @@ -15,7 +15,8 @@ local data = { name: "carbonplanhub.k8s.local" }, spec+: { - configBase: "s3://2i2c-carbonplan-kops-state" + // FIXME: Not sure if this is necessary? + configBase: "s3://2i2c-carbonplan-kops-state/%s" % data.cluster.metadata.name }, _config+:: { zone: zone, @@ -33,7 +34,8 @@ local data = { machineType: "t3.medium", subnets: [zone], nodeLabels+: { - "hub.jupyter.org/pool-name": "core-pool" + "hub.jupyter.org/node-purpose": "core", + "k8s.dask.org/node-purpose": "core" }, // Needs to be at least 1 minSize: 1, @@ -41,7 +43,7 @@ local data = { role: "Master" }, }, - nodes: [ + notebookNodes: [ ig { local thisIg = self, metadata+: { @@ -56,7 +58,8 @@ local data = { maxSize: 20, role: "Node", nodeLabels+: { - "hub.jupyter.org/pool-name": thisIg.metadata.name + "hub.jupyter.org/node-purpose": "user", + "k8s.dask.org/node-purpose": "scheduler" }, taints: [ "hub.jupyter.org_dedicated=user:NoSchedule", @@ -64,10 +67,34 @@ local data = { ], }, } + n for n in nodes + ], + daskNodes: [ + ig { + local thisIg = self, + metadata+: { + labels+: { + "kops.k8s.io/cluster": data.cluster.metadata.name + }, + name: "dask-%s" % std.strReplace(thisIg.spec.machineType, ".", "-") + }, + spec+: { + machineType: n.machineType, + subnets: [zone], + maxSize: 20, + role: "Node", + nodeLabels+: { + "k8s.dask.org/node-purpose": "worker" + }, + taints: [ + "k8s.dask.org_dedicated=worker:NoSchedule", + "k8s.dask.org/dedicated=worker:NoSchedule" + ], + }, + } + n for n in nodes ] }; [ data.cluster, data.master -] + data.nodes \ No newline at end of file +] + data.notebookNodes + data.daskNodes \ No newline at end of file diff --git a/kops/libsonnet/cluster.jsonnet b/kops/libsonnet/cluster.jsonnet index 3384f14ff5..e1c499cad3 100644 --- a/kops/libsonnet/cluster.jsonnet +++ b/kops/libsonnet/cluster.jsonnet @@ -1,4 +1,33 @@ -// local cluster(name, configBase, zone, masterIgName, networkCIDR, subnets) = { +// Exports a customizable kops Cluster object. +// https://kops.sigs.k8s.io/cluster_spec/ lists available properties. +// +// The default configuration sets up the following: +// +// 1. One etcd cluster each on the master node for events & api, +// with minimal resource allocations +// 2. Calico for in-cluster networking https://kops.sigs.k8s.io/networking/calico/, +// with the default settings. Explicitly decided against AWS-VPC cluster networking +// due to pod density issues - see https://github.com/2i2c-org/pangeo-hubs/issues/28. +// 3. Nodes in only one subnet in one AZ. Ideally, the master would be multi-AZ but +// the nodes would be single AZ. Multi AZ workers run into problems attaching PVs +// from other AZs (for hub db PVC, for example), and incurs networking cost for no +// clear benefit in our use case. An opinionated set of IP ranges is picked here, +// and the subnet is created in _config.zone. +// 4. kops defaults for networking - a /16 network for the entire cluster, +// with a /19 allocated to the one subnet currently in use. This allows for +// ~8000 currently active pods. +// 5. Kubernetes API and SSH access allowed from everywhere. +// 6. IAM Permissions to pull from ECR. +// 7. Enables feature gates to allow hub services to run on master node as well. +// 8. Docker as the container runtime. +// +// Supports passing a hidden `_config` object that takes the following +// keys: +// 1. masterInstanceGroupName +// Name of the InstanceGroup that is the master. The etcd clusters will be +// put on this. +// 2. zone +// Zone where the cluster is to be set up { _config+:: { masterInstanceGroupName: "", @@ -63,6 +92,9 @@ anonymousAuth: false, featureGates: { // These boolean values need to be strings + // Without these, services can't target pods running on the master node. + // We want our hub core services to run on the master node, so we need + // to set these. LegacyNodeRoleBehavior: "false", ServiceNodeExclusion: "false" } diff --git a/kops/libsonnet/instancegroup.jsonnet b/kops/libsonnet/instancegroup.jsonnet index e19dcdde7e..5ae4967400 100644 --- a/kops/libsonnet/instancegroup.jsonnet +++ b/kops/libsonnet/instancegroup.jsonnet @@ -1,8 +1,24 @@ +// Exports a customizable kops InstanceGroup object. +// https://kops.sigs.k8s.io/instance_groups/ lists available properties +// of the underlying object. On top of that, the following extra features +// are supported: +// 1. cloudLabels are automatically generated from nodeLabels and taints, +// provided in the appropriate kops format. This is required for the +// cluster autoscaler to function - see +// https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#auto-discovery-setup +// for more information. +// 2. A cloudLabel is added for the `node.kubernetes.io/instance-type` +// label, since we want to target nodes of different sizes with that +// label. Without the cloudLabel, the cluster autoscaler will not know +// which instancegroup to scale up. +// +// Everything else is just passed through to the kops InstanceGroup config local makeCloudLabels(labels) = { ["k8s.io/cluster-autoscaler/node-template/label/%s" % key]: labels[key] for key in std.objectFields(labels) }; + // Kops expects these as strings of form Key=Value:Effect in spec.taints, // but cloudlabels expects them to be key value pairs of Key: Value:Effect local makeCloudTaints(taints) = { @@ -11,22 +27,22 @@ local makeCloudTaints(taints) = { }; -// local instanceGroup(name, clusterName, nodeImage, labels, taints, machineType, subnets, minSize, maxSize, role) = { { - _config+:: { - clusterName: "" - }, apiVersion: "kops.k8s.io/v1alpha2", kind: "InstanceGroup", metadata: { labels+: { - "kops.k8s.io/cluster": $._config.clusterName, + "kops.k8s.io/cluster": "", }, name: "" }, spec: { image: "099720109477/ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20210119.1", - cloudLabels: makeCloudLabels(self.nodeLabels) + makeCloudTaints(self.taints), + cloudLabels: { + // Tell autoscaler to scale up this instancegroup when something asks for a node with the label + // node.kubernetes.io/instance-type: + "k8s.io/cluster-autoscaler/node-template/label/node.kubernetes.io/instance-type": $.spec.machineType + } + makeCloudLabels(self.nodeLabels) + makeCloudTaints(self.taints), taints: [], nodeLabels: {}, machineType: "", diff --git a/kops/setup-efs.py b/kops/setup-efs.py new file mode 100644 index 0000000000..065893209f --- /dev/null +++ b/kops/setup-efs.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +""" +Hacky script to automate EFS setup for a given kops cluster + +1. Create an EFS file system +2. Create a mount target with correct security groups & subnets for + a given kops cluster + +Should be terraform that runs after kops cluster is created and +fetches VPC / SG / Subnets with data sources instead. +""" + +import sys +import boto3 +import secrets +import time + +def find_subnets(cluster_name, region): + """ + Find all the subnets created by kops for this cluster + """ + ec2 = boto3.client('ec2', region_name=region) + return ec2.describe_subnets(Filters=[ + {'Name':'tag:KubernetesCluster', 'Values': [cluster_name]} + ])['Subnets'] + +def find_security_groups(cluster_name, region): + """ + Find security groups of master and nodes of given cluster. + + The EFS mount target needs to be available to the master node of the + cluster too - this is where the hub, proxy, and other core pods live. + The hub-share-creator also runs there. + """ + ec2 = boto3.client('ec2', region_name=region) + return ec2.describe_security_groups(Filters=[ + {'Name':'tag:Name', 'Values': [f'{t}.{cluster_name}' for t in ['masters', 'nodes']]} + ])['SecurityGroups'] + +def create_filesystem(token, cluster_name, region): + """ + Create an EFS filesystem for given cluster + + Sets up a mount target in the appropriate subnets with correct + security groups too. + """ + efs = boto3.client('efs', region_name=region) + subnets = find_subnets(cluster_name, region) + security_groups = find_security_groups(cluster_name, region) + fs = efs.create_file_system( + CreationToken=token, + Encrypted=True, + Backup=True, + Tags=[ + {'Key': 'KubernetesCluster', 'Value': cluster_name} + ] + ) + while True: + resp = efs.describe_file_systems( + CreationToken=token + ) + if resp['FileSystems'][0]['LifeCycleState'] == 'available': + break + time.sleep(5) + + for subnet in subnets: + efs.create_mount_target( + FileSystemId=fs['FileSystemId'], + SubnetId=subnet['SubnetId'], + SecurityGroups=[sg['GroupId'] for sg in security_groups] + ) + print(f'setup {fs["FileSystemId"]}') + +if __name__ == '__main__': + token = secrets.token_hex(16) + create_filesystem(token, sys.argv[1], sys.argv[2]) \ No newline at end of file diff --git a/kops/ssh-keys/carbonplan.key b/kops/ssh-keys/carbonplan.key new file mode 100644 index 0000000000..028b248991 --- /dev/null +++ b/kops/ssh-keys/carbonplan.key @@ -0,0 +1,21 @@ +{ + "data": "ENC[AES256_GCM,data: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,iv:4/eOiYZBFsG1c7bR0wkCYEKBmU53GNFmn+MFmul1GPM=,tag:zQd1K2lk+zXC3DprVbZi/w==,type:str]", + "sops": { + "kms": null, + "gcp_kms": [ + { + "resource_id": "projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs", + "created_at": "2021-05-12T18:14:54Z", + "enc": "CiQA4OM7eEkMq9G2m3gLWS3mrl3HSyHobWRfIsCdb4CUrbySJzMSSQBy9hCY4tQtuh4Y7O3C7EDKKXrTWADp7JNmVKSrzOUyGeIHC7C30CSfpLkwSMBSRw6gfo4eogGFud/TipQ+zGBecVgqA62AA4M=" + } + ], + "azure_kv": null, + "hc_vault": null, + "age": null, + "lastmodified": "2021-05-12T18:14:56Z", + "mac": "ENC[AES256_GCM,data:cR/7XKrPY8TQImjJoeXNTuM+2Vs02Hnu8w8EUgt7nyr498+2brOZt4AeMtknuSN+IJ66qASu8AwP+z1Ofw+TZTRVxtx/BxlzRBI675J7LxlxcV75nNM1VhcZI7AnQTlW3Bi8vbk6BPoZU/IrmJ7ZR2eZohq0MpgSu7VnHgucrck=,iv:R9dg53E+edcAXROW7c4l7El19EWf9V5f14Uc+LCPigk=,tag:4piO7hPnRzyVxgAUfIrbpg==,type:str]", + "pgp": null, + "unencrypted_suffix": "_unencrypted", + "version": "3.7.1" + } +} \ No newline at end of file diff --git a/kops/ssh-keys/carbonplan.key.pub b/kops/ssh-keys/carbonplan.key.pub new file mode 100644 index 0000000000..189ee3a1dc --- /dev/null +++ b/kops/ssh-keys/carbonplan.key.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDfwrdzo3LocJCE1aWU1wcu5BPpEYF/wBhjoRB4VrcGILhQfQjjnTx3fbhsBjiE6v2g0hxpk6LSMPIC86z+faB3c7eutrfLeLtd409xFlEY9RlxX7jYVoIDTrZtO/EyQiAIpNQj9ZBz+vSCReExXRHhy3M5iJm9k9mIQlIR1GCWuvVxDP7/unpGvqkr8GplziUUq9jp+CjtlT2jnUmin7hjEALbXDo0oJpCg3ecy2b3Wr4Pb9cCBCPV1jEoHuNr48qLPjb5mc0ZLoQTxHBmLENQFb+AcOrUhnGD9Yl5vc4Ca+c4kl6hzGXyRtHSxoLE6t/2woq36KqmyZpKlYQACkEmsEu7d8JqPTwWH/JlMwtpSCnvhmYE4L9JO5cnANfsZEBqAnkfaa8uKHCXoNHiI5n37/uLv+v2NaJjSrOEoJUAAERzQ2/xT9fGKhHNRUTZ4pN1EXIi4SdPaBXp368eRGmL3tXy8Qv7mEfwv+XpuBKPdTalEbUP3nxmusOGjT6IjA8= yuvipanda@do-the-work.local diff --git a/secrets/carbonplan.yaml b/secrets/carbonplan.yaml new file mode 100644 index 0000000000..c7086b8dc7 --- /dev/null +++ b/secrets/carbonplan.yaml @@ -0,0 +1,33 @@ +apiVersion: ENC[AES256_GCM,data:Pbg=,iv:n1l/qA/aY7Vdl/9KgRQV90Yprvz14NFcm5Tpzvc2+HE=,tag:jlmp4qMo5APRUYlZOvaWFg==,type:str] +clusters: + - cluster: + certificate-authority-data: ENC[AES256_GCM,data:n4yDTdl1eD2JS8R/gesmA+A9y4tVkZJcHerXlnv9qMRxhY9G9OEwJWhzfoFcf9StjfutTDu34JxkLXkrJETLF/uuvybquas7VEYoG8+8oOrMlfTHa9rrD47VrxOTWBfOd7uBPJSz0A8IuXsI0gNdvb2UlM6HCdOvjF0ldqZudkzFc5R+gkThZqIPZqJGiLlF7s8t0t3mEYnKaKgaYUEuJKGjd9bdrzC944UuVa+bH5XpOG9L1yd1UOxtIucwc5EWUxpRbozSouGOxoBC7ovaGG2WD7KMaSg2Z0GELl6a354K4pCi8hX13VBLuY8Zup5tghLBBr2ADRFdr5J3Q51Fxs/Kr7pQIAs8D/D8zYY3WQRkkeT9OTRi60e3BeYid6s5qbMCk3yK6lyoOEealJy5/i8A5pWuAeqimqMrFpxiUVLHfZL9L7CZIVaQt+WZP8ywQ8OTYhvHp1JrUZvIkerUnzYt/c0b6exBn2E/F4maMTV63KeZUdPINKpplYYRhfeErzvv6cd4BWRMBMFwQOrFD0qtF1IAGpTfTdbB2LNx3jexzMVeJBUmeO1Pizx3VK38YvwLOumbBVwVzlLTtL1p0sr1lLp6qxAXxs6hp3rpMXpAY1rkj2GeYUzWotZhrJhXcUHdqJFl7AIO82AfCZD3q2HXVYwRGPQzTzKaWtUq89ku2ju/eIulwQiL9ktlWjv+12u8Icb1wKlOwO9iwant3qFVjsOrH/qovDx2dJFiANq7ttXOVvmdmmd7Jfp9LUAkyiqo7RmcVDv7bA0jCLRyopiujpFRKW9RjQ8TXtieLmQlmwjbQl08pzr0iApm6K8ldJQLqH4viWEdFnMSSmIB3WtJsJkTV1Srp/fivdhGAgVhTak7TuE9lnl6wAmcDW+A9XewuKCc6b4nm5OqFGscW/Gx0ZvsdgjOlxyr1cCbGj+opi6fgu03oZzq70i4vr4D0hIuXcFW5aC7Rqmg3xz4o2ZZSJ0hlW5I15Lly80otZ9Z0mNIk2koWq4Z1pxN83XhHszhjDiMUePf9Ey71egLKxSMgEJfd21QywXQZSjR9g7LsH6aY9AcNKB2VZcs82bQLakS/FLpXrj+O8ZDx/gnuQQOzaEkweIbSrs4a/cQ+A8DysKHDt1+ibS6wpqYVktwuJ/UgyAd3uwx88YqgRFtV/UDqfb+kpj62riYCyGwk8MIpaB4pyq3G5XxId1Bl4Xf2Or88r2WyKG4/0RROru/8/MFLCNVS2t/TNArdzoFYM0GP2ORP5SZBc+yp10CUtHGN8esAdXvEMvIUy1lSauH3e9nXrGy6MbcMIoy/dYdKah0gkfeLA/yTZFja3vLdHX06I3PL4LhwvYZLKIeLVufIxQM4dA1odchM3Xwdd0MPvUMyRwLEDcLTU2Vzh1ePnGEZfdSpbXqe2UqaHQ23H+0WiAZ1ziNhxFJ9AqJDffoXqhmhW0RVeIV3WFcpfWPFck/kWtHq+5kGWkD3on107HlRnnxr8FTDwRmmARi5rGBRCsxa6S0nC+R5mIVk7Zb3UQl2ihuFG0dpVDCNW5D+xcAxfqfj7SC8VFkXMZ8FidQ79ybymQxIs0TFIaHR7nfpdnlbVX3ww3iMmBNr29OofcdG0xA14cn/Zg21W87m8UNCI5XrCD2y7QUVWkDVsmLfcgulC002sdWKBSejF/wWnJvo4jDCrhtbEv7nulgnc6JEkOXJWkoJTAPKzn6JDgIdzaD+Pttc6GgT9tjYKktPwqyc4vu3UddvwPr+xryiVkppVEnC/dFe5YLQgcF2DNfl/QCRc0vkP4TVCxebDzTp6m5gOqUsiA56pbrt/6sxpvFnEHC3Almr9/S6WeZ1cy0ZVPZG6UwtMaqoPr74ifZM1hiOsya5WdPNss66i2YvwqidUg/ows1/WGHW2/lgwXFfowcpskMCQ==,iv:zx3p5elDZqZTLRDJ6o1ErzF/3V+MSSjSsnERXAAkzw4=,tag:pR1xurZ/FwpH0I9NFzHoBg==,type:str] + server: ENC[AES256_GCM,data:LjzyspIiCGHCzTtLBLIXMD19cKbvygWBePlyFma2rzNvXlzcSdwGI4/WWz8MBJIsGhaTGALGRX2thDBXhzlBWIXWUpvYYntignbRVkziDQ==,iv:t5P2kKIx2WbI4IbQ25hoeIBAwYV7zTG5IkxVWhpzAiQ=,tag:97p0meCGUsEayhYhfzpDfg==,type:str] + name: ENC[AES256_GCM,data:m/BXWox6HSwgZCfzWbVEn/ofhectLYc=,iv:EFwTN64w0HtaATtccTf2jbqEJzbaaJEKqwVhFXAX8B0=,tag:M716LDPkFLFHXE1U/zUlxA==,type:str] +contexts: + - context: + cluster: ENC[AES256_GCM,data:8ZoXepVShI+VJCwsyXQWsW6jDlrWFnQ=,iv:CWz4gPSdsmC1YSSUyaxeFl3kwAH8FlNji+4wPv8IpIM=,tag:IZnk69WKJm3TE/OyxhccGQ==,type:str] + user: ENC[AES256_GCM,data:WW05SXoMIvNCiWf8wyoisS4IZ+peARU=,iv:rl9CzzOJnEwOKWICxXn5TdSbJufALNtjwDgaH8BXYHc=,tag:9z5Yoy5zDH9UbzIEui7vXw==,type:str] + name: ENC[AES256_GCM,data:SwJGWxvcjagEThk196jML7l+AKP0KF0=,iv:j7j7hcdCq2N/h82nHasjX/cU8naNTtQxMvb19xjz2cY=,tag:R/f+lHVe80JGXXgLOFo89A==,type:str] +current-context: ENC[AES256_GCM,data:53+XhFN7WM5hJZ25YXdJzHzSosb5tys=,iv:MfY1K7R35s/gjRAkxkyrKUmuWjKPSyLl+OQOF/ZLQyQ=,tag:hbWJhcLDK62KM+63Xzu9Yg==,type:str] +kind: ENC[AES256_GCM,data:VkFwX3PV,iv:5p7fQVOi63lXt6RLlRlLt4s48feGCG5pc/t8UZbj75E=,tag:G2ZWqupWmWKxvGzlnybIag==,type:str] +preferences: {} +users: + - name: ENC[AES256_GCM,data:IzJTzad6TXkbuDuEQHfUHMbS3IexYo4=,iv:igfNhn+1x9FLLYvum2pN4UWu9cPKAvR6l9Az1oieILA=,tag:LmQ9ArMAsBjdPG6lOOZQqA==,type:str] + user: + client-certificate-data: ENC[AES256_GCM,data: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,iv:HGOaid3oUh1kWKKzuL+FGeVRpgsI+OQdrvzZVa7dbeI=,tag:jSAxEKErekVhm5I+Aggb2Q==,type:str] + client-key-data: ENC[AES256_GCM,data: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,iv:2ikCP0ls3Fn3yMTU/L/ax3bSxteYxqk5FUocl6QAkzM=,tag:hvsG8Rqdx0sZ73+hN+MQUw==,type:str] +sops: + kms: [] + gcp_kms: + - resource_id: projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs + created_at: "2021-05-11T17:42:53Z" + enc: CiQA4OM7eAi+MGH3STjMg9uCkPhlJLinqBkbsd50JHoUbFJ1ya0SSQBy9hCYkSPMrZmzLIuLrzSfa8SqY11Xn4nGQJq7gBw6qArdSOOJe2iIoGyeBN4XftmGJQT2EB+5UeNQk0nO4Dw3FMehcacKCuA= + azure_kv: [] + hc_vault: [] + age: [] + lastmodified: "2021-05-11T17:42:55Z" + mac: ENC[AES256_GCM,data:4IPo4SH3mjiS5iE9BthCDp31d5OB4YA7HAjHG21O57e5A3f7J/bTt4acA0fYmf6FiCtb6UxKwyIRxsRfgsjVfkBY0VgLMdqNDijn6nqTt1roObWwoXmI7KkpqlWPTuUz9doTwPLje35sY+kBaLuhv/QCPabkul4n9S7trb1wYQQ=,iv:khILySofUGqHZMIT7zRilnwJLFCpSAfY0oZcJzrgb40=,tag:l+UZr8L+i54YdKA9vh2EQg==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.7.1