diff --git a/.gitignore b/.gitignore index 9869ee2..77a952c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -.last-modified +.last_modified diff --git a/gcp/environment/README.md b/gcp/environment/README.md new file mode 100644 index 0000000..afc6bec --- /dev/null +++ b/gcp/environment/README.md @@ -0,0 +1,26 @@ +# GCP Environment Workflow + +This workflow provisions and configures a GCP-based environment using the `koreo.dev` workflow engine and custom `ResourceFunction` and `ValueFunction` modules. + +Included in the environment are a VPC, Subnet, and Firewall. + +## Overview + +- **CRD Reference**: Targets the `GcpEnvironment` CRD defined under `example.koreo.dev/v1beta1`. +- **Inputs**: Expects a `parent` object. +- **Output**: An example vpc and subnet with a firewall + +## Workflow Steps + +| Step | Description | +|------|-------------| +| `metadata` | Generates standard metadata used across all resources. | +| `network` | Creates a VPC network for the environment. | +| `subnet` | Provisions a subnet within the created VPC with CIDR `10.10.0.0/16`. | +| `firewall` | Configures firewall rules for the subnet. | + +## Requirements + +- GCP project with appropriate APIs enabled (IAM, Compute Engine). +- Koreo engine with support for `ResourceFunction` and `ValueFunction`. +- IAM permissions to create the various vpc resources diff --git a/gcp/vpc/gcp-environment-crd.yaml b/gcp/environment/crd/gcp-environment-crd.yaml similarity index 97% rename from gcp/vpc/gcp-environment-crd.yaml rename to gcp/environment/crd/gcp-environment-crd.yaml index 4693b24..e02eb45 100644 --- a/gcp/vpc/gcp-environment-crd.yaml +++ b/gcp/environment/crd/gcp-environment-crd.yaml @@ -1,10 +1,10 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: - name: gcpenvironments.acme.example.com + name: gcpenvironments.example.koreo.dev spec: scope: Namespaced - group: acme.example.com + group: example.koreo.dev names: kind: GcpEnvironment plural: gcpenvironments diff --git a/gcp/vpc/firewall.k.yaml b/gcp/environment/firewall.k.yaml similarity index 60% rename from gcp/vpc/firewall.k.yaml rename to gcp/environment/firewall.k.yaml index 29bf5c2..1d066e5 100644 --- a/gcp/vpc/firewall.k.yaml +++ b/gcp/environment/firewall.k.yaml @@ -1,3 +1,4 @@ +--- apiVersion: koreo.dev/v1beta1 kind: ResourceFunction metadata: @@ -11,26 +12,24 @@ spec: resource: spec: - allow: - - ports: - - 0-65535 - protocol: tcp - - ports: - - 0-65535 - protocol: udp - - protocol: icmp - direction: INGRESS networkRef: name: =inputs.networkName - sourceRanges: + allow: + - protocol: tcp + ports: ["0-65535"] + - protocol: udp + ports: ["0-65535"] + - protocol: icmp + sourceRanges: - =inputs.subnet.range - + direction: INGRESS + postconditions: - assert: =resource.config_connect_ready() retry: - delay: 10 message: Waiting for firewall to be created - + delay: 10 + return: name: =inputs.metadata.name --- @@ -44,32 +43,30 @@ spec: name: gcp-environment-firewall inputs: + networkName: test-network-name metadata: name: test-network namespace: test-namespace - networkName: test-network-name subnet: name: subnet1 range: 10.0.0.0/20 - + testCases: - - expectResource: - apiVersion: compute.cnrm.cloud.google.com/v1beta1 - kind: ComputeFirewall - metadata: - name: test-network - namespace: test-namespace - spec: - allow: - - ports: - - 0-65535 - protocol: tcp - - ports: - - 0-65535 - protocol: udp - - protocol: icmp - direction: INGRESS - networkRef: - name: test-network-name - sourceRanges: - - 10.0.0.0/20 + - expectResource: + apiVersion: compute.cnrm.cloud.google.com/v1beta1 + kind: ComputeFirewall + metadata: + name: test-network + namespace: test-namespace + spec: + allow: + - protocol: tcp + ports: ["0-65535"] + - protocol: udp + ports: ["0-65535"] + - protocol: icmp + sourceRanges: + - 10.0.0.0/20 + direction: INGRESS + networkRef: + name: test-network-name \ No newline at end of file diff --git a/gcp/environment/fixtures/environment.yaml b/gcp/environment/fixtures/environment.yaml new file mode 100644 index 0000000..245c5f2 --- /dev/null +++ b/gcp/environment/fixtures/environment.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: example.koreo.dev/v1 +kind: GcpEnvironment +metadata: + name: my-environment +spec: + description: My GCP environment diff --git a/gcp/environment/metadata.k.yaml b/gcp/environment/metadata.k.yaml new file mode 100644 index 0000000..6c9ef91 --- /dev/null +++ b/gcp/environment/metadata.k.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: koreo.dev/v1beta1 +kind: ValueFunction +metadata: + name: gcp-environment-metadata +spec: + return: + name: =inputs.environmentResourceName + namespace: =inputs.environmentNamespace +--- +apiVersion: koreo.dev/v1beta1 +kind: FunctionTest +metadata: + name: gcp-environment-metadata-test +spec: + functionRef: + name: gcp-environment-metadata + kind: ValueFunction + inputs: + environmentResourceName: example-test + environmentNamespace: example-ns + testCases: + - expectReturn: + name: example-test + namespace: example-ns + \ No newline at end of file diff --git a/gcp/vpc/network.k.yaml b/gcp/environment/network.k.yaml similarity index 72% rename from gcp/vpc/network.k.yaml rename to gcp/environment/network.k.yaml index 75f808b..941ae9d 100644 --- a/gcp/vpc/network.k.yaml +++ b/gcp/environment/network.k.yaml @@ -1,3 +1,4 @@ +--- apiVersion: koreo.dev/v1beta1 kind: ResourceFunction metadata: @@ -11,18 +12,19 @@ spec: resource: spec: + routingMode: REGIONAL autoCreateSubnetworks: false enableUlaInternalIpv6: false - routingMode: REGIONAL - + postconditions: - assert: =resource.config_connect_ready() retry: - delay: 10 message: Waiting for compute network to be created - + delay: 10 + return: name: =inputs.metadata.name + --- apiVersion: koreo.dev/v1beta1 kind: FunctionTest @@ -37,15 +39,15 @@ spec: metadata: name: test-network namespace: test-namespace - + testCases: - - expectResource: - apiVersion: compute.cnrm.cloud.google.com/v1beta1 - kind: ComputeNetwork - metadata: - name: test-network - namespace: test-namespace - spec: - autoCreateSubnetworks: false - enableUlaInternalIpv6: false - routingMode: REGIONAL + - expectResource: + apiVersion: compute.cnrm.cloud.google.com/v1beta1 + kind: ComputeNetwork + metadata: + name: test-network + namespace: test-namespace + spec: + routingMode: REGIONAL + autoCreateSubnetworks: false + enableUlaInternalIpv6: false \ No newline at end of file diff --git a/gcp/vpc/subnet.k.yaml b/gcp/environment/subnet.k.yaml similarity index 54% rename from gcp/vpc/subnet.k.yaml rename to gcp/environment/subnet.k.yaml index e4f315e..0827782 100644 --- a/gcp/vpc/subnet.k.yaml +++ b/gcp/environment/subnet.k.yaml @@ -1,3 +1,4 @@ +--- apiVersion: koreo.dev/v1beta1 kind: ResourceFunction metadata: @@ -11,17 +12,22 @@ spec: resource: spec: - ipCidrRange: =inputs.range networkRef: name: =inputs.networkName region: us-central1 - + ipCidrRange: =inputs.range + secondaryIpRange: + - rangeName: servicesrange + ipCidrRange: =inputs.servicesRange + - rangeName: clusterrange + ipCidrRange: =inputs.clusterRange + postconditions: - assert: =resource.config_connect_ready() retry: - delay: 10 message: Waiting for subnetwork to be created - + delay: 10 + return: name: =inputs.metadata.name range: =inputs.range @@ -36,21 +42,28 @@ spec: name: gcp-environment-subnet inputs: + range: 10.0.0.0/16 + servicesRange: 10.11.0.0/16 + clusterRange: 10.12.0.0/16 + networkName: test-network-name metadata: name: test-network namespace: test-namespace - networkName: test-network-name - range: 10.0.0.0/16 - + testCases: - - expectResource: - apiVersion: compute.cnrm.cloud.google.com/v1beta1 - kind: ComputeSubnetwork - metadata: - name: test-network - namespace: test-namespace - spec: - ipCidrRange: 10.0.0.0/16 - networkRef: - name: test-network-name - region: us-central1 + - expectResource: + apiVersion: compute.cnrm.cloud.google.com/v1beta1 + kind: ComputeSubnetwork + metadata: + name: test-network + namespace: test-namespace + spec: + region: us-central1 + ipCidrRange: 10.0.0.0/16 + networkRef: + name: test-network-name + secondaryIpRange: + - rangeName: servicesrange + ipCidrRange: 10.11.0.0/16 + - rangeName: clusterrange + ipCidrRange: 10.12.0.0/16 \ No newline at end of file diff --git a/gcp/vpc/workflow.k.yaml b/gcp/environment/workflow.k.yaml similarity index 71% rename from gcp/vpc/workflow.k.yaml rename to gcp/environment/workflow.k.yaml index 8c881be..c467f62 100644 --- a/gcp/vpc/workflow.k.yaml +++ b/gcp/environment/workflow.k.yaml @@ -4,26 +4,25 @@ metadata: name: gcp-environment spec: crdRef: - apiGroup: acme.example.com - kind: GcpEnvironment + apiGroup: example.koreo.dev version: v1beta1 - + kind: GcpEnvironment + steps: - - label: config + - label: metadata ref: + name: gcp-environment-metadata kind: ValueFunction - name: gcp-environment-config inputs: - parent: =parent - state: - projectId: =value.projectId + environmentResourceName: =parent.metadata.name + environmentNamespace: =parent.metadata.namespace - label: network ref: kind: ResourceFunction name: gcp-environment-network inputs: - metadata: =steps.config + metadata: =steps.metadata state: networkName: =value.name @@ -32,7 +31,7 @@ spec: kind: ResourceFunction name: gcp-environment-subnet inputs: - metadata: =steps.config + metadata: =steps.metadata networkName: =steps.network.name range: 10.10.0.0/16 state: @@ -43,6 +42,6 @@ spec: kind: ResourceFunction name: gcp-environment-firewall inputs: - metadata: =steps.config + metadata: =steps.metadata networkName: =steps.network.name subnet: =steps.subnet diff --git a/gcp/federated-gke/README.md b/gcp/federated-gke/README.md new file mode 100644 index 0000000..19508d8 --- /dev/null +++ b/gcp/federated-gke/README.md @@ -0,0 +1,146 @@ +# Federated GKE Workflow + +This workflow provisions and configures a complete Kubernetes cluster in another project and creates +a k8s service account in the Koreo Cluster with `roles/container.developer` access to it +using the `koreo.dev` workflow engine and custom `ResourceFunction` and `ValueFunction` modules. + +The workflow creates a GKE cluster, necessary IAM and K8s service accounts, sets up Workload Identity to allow Kubernetes ServiceAccounts to impersonate GCP Service Accounts securely. + +## Overview + +- **CRD Reference**: Targets the `FederatedGKE` CRD defined under `example.koreo.dev/v1beta1`. +- **Inputs**: Expects a `parent` object, that has a networkName, subnetworkName, and projectId input. +- **Output**: A fully provisioned Kubernetes cluster with Workload Identity configured. + +## Workflow Steps + +| Step | Description | +|------|-------------| +| `metadata` | Generates standard metadata used across all resources. | +| `k8sCluster` | Provisions a GKE cluster using the created VPC and subnet. | +| `k8sClusterSecret` | Extracts the Kubernetes API endpoint and CA cert to create a Kubernetes config secret. | +| `workloadIdentityServiceAccount` | Creates a GCP IAM Service Account used for Workload Identity. | +| `workloadIdentityPolicyMember` | Grants the IAM service account the necessary project-level permissions. | +| `ksaServiceAccount` | Creates a Kubernetes Service Account (KSA) annotated to impersonate the IAM Service Account. | +| `workloadIdentityPolicyMemberIdentKSA` | Grants the IAM service account permission to be impersonated by the KSA (`iam.workloadIdentityUser`). | +| `workloadIdentityPolicyMemberTokenKSA` | Grants the KSA permission to create identity tokens on behalf of the IAM service account (`iam.serviceAccountTokenCreator`). | + +## Requirements + +- GCP project with appropriate APIs enabled (IAM, GKE, Compute Engine). +- Koreo engine with support for `ResourceFunction` and `ValueFunction`. +- IAM permissions to create networks, clusters, service accounts, and IAM policies. + +## Federated Koreo + +- To have a subsequent Koreo install use the created k8s service account and manage resources in it, you will need edit the above workflow to use the service account created in the `federated-k8s-service-account` step or run the following commands or edit the koreo service account name. + +## Debug Sanity Check + +- Ensure Koreo service account has permissions to edit IAM policy + - I made it owner of the account, but this could be restricted I am sure. +- Ensure Identity and Access Management API is enabled +- Ensure Kubernetes API is enabled +- Ensure Cloud Resource Manager API is enabled + + +``` sh +gcloud projects add-iam-policy-binding \ + --member="serviceAccount:@.iam.gserviceaccount.com" \ + --role="roles/container.developer" +``` + +``` sh +gcloud iam service-accounts add-iam-policy-binding \ + @.iam.gserviceaccount.com \ + --role "roles/iam.workloadIdentityUser" \ + --member "serviceAccount:.svc.id.goog[/koreo]" +``` + +``` sh +gcloud iam service-accounts add-iam-policy-binding \ + @.iam.gserviceaccount.com \ + --role "roles/iam.serviceAccountTokenCreator" \ + --member "serviceAccount:.svc.id.goog[/koreo]" +``` + +### Validate Service Account + +``` sh +# Edit serviceAccountName to koreo or whatever the workflow generates ("-workload-ksa") +# Edit the secret name references to the FederatedGKE instance name +kubectl apply -f ./fixtures/validation-pod.yaml + +kubectl exec -it -n federated-k8s -- /bin/sh + +$ pip install pykube-ng google-auth +$ python +``` + +Run the following script to ensure your connection is working. + +``` python +import os +import base64 +import tempfile +import yaml +from google.auth.transport.requests import Request +from google.auth import default +import pykube +from pykube import HTTPClient, KubeConfig + +# Decode credentials passed in as env vars +cert = os.environ["GKE_CLUSTER_CA"].encode() +if cert.startswith(b"LS0"): + cert = base64.b64decode(cert) # only decode once if still encoded + +token = None +creds, _ = default() +creds.refresh(Request()) +token = creds.token + +# Clean up endpoint +endpoint = os.environ["GKE_CLUSTER_ENDPOINT"] +if endpoint.startswith("https://"): + endpoint = endpoint[len("https://"):] + +# Build minimal kubeconfig +kubeconfig = { + "apiVersion": "v1", + "kind": "Config", + "clusters": [{ + "name": "inline", + "cluster": { + "server": f"https://{endpoint}", + "certificate-authority-data": base64.b64encode(cert).decode(), + }, + }], + "users": [{ + "name": "inline", + "user": { + "token": token, + }, + }], + "contexts": [{ + "name": "inline", + "context": { + "cluster": "inline", + "user": "inline", + }, + }], + "current-context": "inline", +} + +# Write to a named temporary file +kubeconfig_path = "/tmp/inline-kubeconfig.yaml" +with open(kubeconfig_path, "w") as f: + yaml.safe_dump(kubeconfig, f) + +print(f"Wrote kubeconfig to {kubeconfig_path}") + +# Load and use it +api = HTTPClient(KubeConfig.from_file(kubeconfig_path)) + +for pod in pykube.Pod.objects(api).filter(namespace="kube-system"): + print(pod.name) +``` diff --git a/gcp/federated-gke/crd/federated-gke-crd.yaml b/gcp/federated-gke/crd/federated-gke-crd.yaml new file mode 100644 index 0000000..6db0c8c --- /dev/null +++ b/gcp/federated-gke/crd/federated-gke-crd.yaml @@ -0,0 +1,80 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: federatedgke.example.koreo.dev +spec: + scope: Namespaced + group: example.koreo.dev + names: + kind: FederatedGKE + plural: federatedgkes + singular: federatedgke + versions: + - name: v1beta1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + apiVersion: + description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources" + type: string + kind: + description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" + type: string + metadata: + type: object + spec: + type: object + properties: + description: + description: The description of the environment + nullable: true + type: string + subnetworkName: + description: The gcp subnetwork name to use for the cluster + type: string + networkName: + description: The gcp network name to use for the cluster + type: string + projectId: + description: The gcp project id + type: string + status: + x-kubernetes-preserve-unknown-fields: true + properties: + conditions: + description: + Conditions represent the latest available observation + of the resource's current state. + items: + properties: + lastTransitionTime: + description: + Last time the condition transitioned from one status + to another. + type: string + message: + description: + Human-readable message indicating details about + last transition. + type: string + reason: + description: + Unique, one-word, CamelCase reason for the condition's + last transition. + type: string + status: + description: + Status is the status of the condition. Can be True, + False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + type: array + type: object + required: + - spec diff --git a/gcp/federated-gke/fixtures/cluster.yaml b/gcp/federated-gke/fixtures/cluster.yaml new file mode 100644 index 0000000..99a4972 --- /dev/null +++ b/gcp/federated-gke/fixtures/cluster.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: example.koreo.dev/v1 +kind: FederatedGke +metadata: + name: my-cluster +spec: + projectId: my-project-id + networkName: my-network + subnetworkName: my-subnetwork diff --git a/gcp/federated-gke/fixtures/validation-pod.yaml b/gcp/federated-gke/fixtures/validation-pod.yaml new file mode 100644 index 0000000..3889ea4 --- /dev/null +++ b/gcp/federated-gke/fixtures/validation-pod.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Pod +metadata: + name: federated-k8s +spec: + serviceAccountName: dev-workload-ksa # This is the name of the KSA created by the federated-k8s-service-account function + containers: + - name: app + image: python:3.11 + command: ["sleep", "infinity"] + env: + - name: GKE_CLUSTER_ENDPOINT + valueFrom: + secretKeyRef: + name: dev + key: endpoint + - name: GKE_CLUSTER_CA + valueFrom: + secretKeyRef: + name: dev + key: ca.crt diff --git a/gcp/federated-gke/iam_policy_member.k.yaml b/gcp/federated-gke/iam_policy_member.k.yaml new file mode 100644 index 0000000..ffa58f3 --- /dev/null +++ b/gcp/federated-gke/iam_policy_member.k.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: koreo.dev/v1beta1 +kind: ResourceFunction +metadata: + name: federated-iam-policy-member +spec: + locals: + name: =inputs.metadata.name + "-workload-identity" + apiConfig: + apiVersion: iam.cnrm.cloud.google.com/v1beta1 + kind: IAMPolicyMember + name: =locals.name + namespace: =inputs.metadata.namespace + + resource: + spec: + member: =inputs.saMember + role: roles/container.developer + resourceRef: + kind: Project + external: ="projects/" + inputs.projectId + + postconditions: + - assert: =resource.config_connect_ready() + retry: + message: Waiting for connector to be created + delay: 10 + + return: + name: =locals.name diff --git a/gcp/federated-gke/iam_policy_member_ident_ksa.k.yaml b/gcp/federated-gke/iam_policy_member_ident_ksa.k.yaml new file mode 100644 index 0000000..e08d41e --- /dev/null +++ b/gcp/federated-gke/iam_policy_member_ident_ksa.k.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: koreo.dev/v1beta1 +kind: ResourceFunction +metadata: + name: federated-iam-policy-member-ident-ksa +spec: + locals: + name: =inputs.metadata.name + "-ksa-ident-user" + apiConfig: + apiVersion: iam.cnrm.cloud.google.com/v1beta1 + kind: IAMPolicyMember + name: =locals.name + namespace: =inputs.metadata.namespace + + resource: + spec: + member: ="serviceAccount:" + inputs.projectId + ".svc.id.goog[" + inputs.metadata.namespace + "/" + inputs.ksaName + "]" + role: roles/iam.workloadIdentityUser + resourceRef: + kind: IAMServiceAccount + name: =inputs.saName + postconditions: + - assert: =resource.config_connect_ready() + retry: + message: Waiting for identity policy member to be created + delay: 10 + + return: + name: =locals.name diff --git a/gcp/federated-gke/iam_policy_member_token_ksa.k.yaml b/gcp/federated-gke/iam_policy_member_token_ksa.k.yaml new file mode 100644 index 0000000..86a3081 --- /dev/null +++ b/gcp/federated-gke/iam_policy_member_token_ksa.k.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: koreo.dev/v1beta1 +kind: ResourceFunction +metadata: + name: federated-iam-policy-member-token-ksa +spec: + locals: + name: =inputs.metadata.name + "-ksa-token-user" + apiConfig: + apiVersion: iam.cnrm.cloud.google.com/v1beta1 + kind: IAMPolicyMember + name: =locals.name + namespace: =inputs.metadata.namespace + + resource: + spec: + member: ="serviceAccount:" + inputs.projectId + ".svc.id.goog[" + inputs.metadata.namespace + "/" + inputs.ksaName + "]" + role: roles/iam.serviceAccountTokenCreator + resourceRef: + kind: IAMServiceAccount + name: =inputs.saName + postconditions: + - assert: =resource.config_connect_ready() + retry: + message: Waiting for token member to be created + delay: 10 + + return: + name: =locals.name diff --git a/gcp/federated-gke/iam_service_account.k.yaml b/gcp/federated-gke/iam_service_account.k.yaml new file mode 100644 index 0000000..1d78072 --- /dev/null +++ b/gcp/federated-gke/iam_service_account.k.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: koreo.dev/v1beta1 +kind: ResourceFunction +metadata: + name: federated-iam-service-account +spec: + locals: + name: =inputs.metadata.name + "-workload-identity" + apiConfig: + apiVersion: iam.cnrm.cloud.google.com/v1beta1 + kind: IAMServiceAccount + name: =locals.name + namespace: =inputs.metadata.namespace + + resource: + spec: + displayName: "GKE remote access via Workload Identity" + + postconditions: + - assert: =resource.config_connect_ready() + retry: + message: Waiting for connector to be created + delay: 10 + + return: + name: =locals.name + member: =resource.status.member diff --git a/gcp/federated-gke/k8s_cluster.k.yaml b/gcp/federated-gke/k8s_cluster.k.yaml new file mode 100644 index 0000000..c8d6564 --- /dev/null +++ b/gcp/federated-gke/k8s_cluster.k.yaml @@ -0,0 +1,68 @@ +--- + apiVersion: koreo.dev/v1beta1 + kind: ResourceFunction + metadata: + name: federated-k8s-cluster + spec: + apiConfig: + apiVersion: container.cnrm.cloud.google.com/v1beta1 + kind: ContainerCluster + name: =inputs.metadata.name + namespace: =inputs.metadata.namespace + + resource: + spec: + description: A large regional VPC-native cluster set up with special networking considerations. + location: us-central1 + initialNodeCount: 1 + defaultMaxPodsPerNode: 16 + nodeLocations: + - us-central1-a + - us-central1-b + - us-central1-c + - us-central1-f + workloadIdentityConfig: + workloadPool: skybit-systems.svc.id.goog + networkingMode: VPC_NATIVE + networkRef: + name: =inputs.networkName + subnetworkRef: + name: =inputs.subnetworkName + ipAllocationPolicy: + servicesSecondaryRangeName: servicesrange + clusterSecondaryRangeName: clusterrange + clusterAutoscaling: + enabled: true + autoscalingProfile: BALANCED + resourceLimits: + - resourceType: cpu + maximum: 100 + minimum: 10 + - resourceType: memory + maximum: 1000 + minimum: 100 + maintenancePolicy: + dailyMaintenanceWindow: + startTime: 00:00 + releaseChannel: + channel: STABLE + enableBinaryAuthorization: true + enableIntranodeVisibility: true + enableShieldedNodes: true + addonsConfig: + networkPolicyConfig: + disabled: false + networkPolicy: + enabled: true + podSecurityPolicyConfig: + enabled: true + + postconditions: + - assert: =resource.config_connect_ready() + retry: + message: Waiting for GKE Cluster to be created + delay: 30 + + return: + endpoint: ="https://" + resource.status.observedState.privateClusterConfig.publicEndpoint + caCert: =resource.status.observedState.masterAuth.clusterCaCertificate \ No newline at end of file diff --git a/gcp/federated-gke/k8s_cluster_secret.k.yaml b/gcp/federated-gke/k8s_cluster_secret.k.yaml new file mode 100644 index 0000000..552da45 --- /dev/null +++ b/gcp/federated-gke/k8s_cluster_secret.k.yaml @@ -0,0 +1,21 @@ +--- + apiVersion: koreo.dev/v1beta1 + kind: ResourceFunction + metadata: + name: federated-k8s-cluster-secret + spec: + apiConfig: + apiVersion: v1 + kind: Secret + name: =inputs.metadata.name + namespace: =inputs.metadata.namespace + + resource: + type: Opaque + data: + endpoint: =b64encode(inputs.endpoint) + ca.crt: =b64encode(inputs.caCert) + + return: + name: =inputs.metadata.name + \ No newline at end of file diff --git a/gcp/federated-gke/k8s_service_account.k.yaml b/gcp/federated-gke/k8s_service_account.k.yaml new file mode 100644 index 0000000..9fe83c0 --- /dev/null +++ b/gcp/federated-gke/k8s_service_account.k.yaml @@ -0,0 +1,21 @@ +--- + apiVersion: koreo.dev/v1beta1 + kind: ResourceFunction + metadata: + name: federated-k8s-service-account + spec: + locals: + name: =inputs.metadata.name + "-workload-ksa" + apiConfig: + apiVersion: v1 + kind: ServiceAccount + name: =locals.name + namespace: =inputs.metadata.namespace + + resource: + metadata: + annotations: + iam.gke.io/gcp-service-account: =inputs.saName + "@" + inputs.projectId + ".iam.gserviceaccount.com" + return: + name: =locals.name + \ No newline at end of file diff --git a/gcp/federated-gke/metadata.k.yaml b/gcp/federated-gke/metadata.k.yaml new file mode 100644 index 0000000..825369f --- /dev/null +++ b/gcp/federated-gke/metadata.k.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: koreo.dev/v1beta1 +kind: ValueFunction +metadata: + name: federated-metadata +spec: + return: + name: =inputs.clusterResourceName + namespace: =inputs.clusterNamespace +--- +apiVersion: koreo.dev/v1beta1 +kind: FunctionTest +metadata: + name: federated-metadata-test +spec: + functionRef: + name: federated-metadata + kind: ValueFunction + inputs: + clusterResourceName: example-test + clusterNamespace: example-ns + testCases: + - expectReturn: + name: example-test + namespace: example-ns diff --git a/gcp/federated-gke/workflow.k.yaml b/gcp/federated-gke/workflow.k.yaml new file mode 100644 index 0000000..0936cbe --- /dev/null +++ b/gcp/federated-gke/workflow.k.yaml @@ -0,0 +1,83 @@ +apiVersion: koreo.dev/v1beta1 +kind: Workflow +metadata: + name: federated-gke +spec: + crdRef: + apiGroup: example.koreo.dev + version: v1beta1 + kind: FederatedGKE + + steps: + - label: metadata + ref: + name: federated-metadata + kind: ValueFunction + inputs: + clusterResourceName: =parent.metadata.name + clusterNamespace: =parent.metadata.namespace + + - label: k8sCluster + ref: + kind: ResourceFunction + name: federated-k8s-cluster + inputs: + metadata: =steps.metadata + networkName: =parent.networkName + subnetworkName: =parent.subnetworkName + state: + k8sCluster: =value + + - label: k8sClusterSecret + ref: + kind: ResourceFunction + name: federated-k8s-cluster-secret + inputs: + metadata: =steps.metadata + endpoint: =steps.k8sCluster.endpoint + caCert: =steps.k8sCluster.caCert + + - label: workloadIdentityServiceAccount + ref: + kind: ResourceFunction + name: federated-iam-service-account + inputs: + metadata: =steps.metadata + + - label: workloadIdentityPolicyMember + ref: + kind: ResourceFunction + name: federated-iam-policy-member + inputs: + metadata: =steps.metadata + saMember: =steps.workloadIdentityServiceAccount.member + projectId: =parent.spec.projectId + + - label: ksaServiceAccount + ref: + kind: ResourceFunction + name: federated-k8s-service-account + inputs: + metadata: =steps.metadata + saName: =steps.workloadIdentityServiceAccount.name + projectId: =parent.spec.projectId + + - label: workloadIdentityPolicyMemberIdentKSA + ref: + kind: ResourceFunction + name: federated-iam-policy-member-ident-ksa + inputs: + metadata: =steps.metadata + saName: =steps.workloadIdentityServiceAccount.name + ksaName: =steps.ksaServiceAccount.name + projectId: =parent.spec.projectId + + - label: workloadIdentityPolicyMemberTokenKSA + ref: + kind: ResourceFunction + name: federated-iam-policy-member-token-ksa + inputs: + metadata: =steps.metadata + saName: =steps.workloadIdentityServiceAccount.name + ksaName: =steps.ksaServiceAccount.name + projectId: =parent.spec.projectId \ No newline at end of file diff --git a/gcp/vpc/README.md b/gcp/vpc/README.md deleted file mode 100644 index c5b326b..0000000 --- a/gcp/vpc/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# VPC - -This example demonstrates building a VPC with a subnet and firewall that is -exposed through a GcpEnvironment abstraction. This uses [Config Connector](https://cloud.google.com/config-connector/docs/overview) -for provisioning GCP resources. diff --git a/gcp/vpc/config.k.yaml b/gcp/vpc/config.k.yaml deleted file mode 100644 index 16f9f16..0000000 --- a/gcp/vpc/config.k.yaml +++ /dev/null @@ -1,34 +0,0 @@ -apiVersion: koreo.dev/v1beta1 -kind: ValueFunction -metadata: - name: gcp-environment-config -spec: - return: - environmentNamespace: =inputs.parent.metadata.namespace - environmentResourceName: =inputs.parent.metadata.name - projectId: =inputs.parent.spec.projectId ---- -apiVersion: koreo.dev/v1beta1 -kind: FunctionTest -metadata: - name: gcp-environment-config-test -spec: - functionRef: - kind: ValueFunction - name: gcp-environment-config - - inputs: - parent: - apiVersion: acme.example.com/v1beta1 - kind: GcpEnvironment - metadata: - name: test-gcp-environment - namespace: test-namespace - spec: - projectId: test-project - - testCases: - - expectReturn: - environmentNamespace: test-namespace - environmentResourceName: test-gcp-environment - projectId: test-project diff --git a/gcp/vpc/gcp-environment.yaml b/gcp/vpc/gcp-environment.yaml deleted file mode 100644 index d7714e0..0000000 --- a/gcp/vpc/gcp-environment.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: acme.example.com/v1beta1 -kind: GcpEnvironment -metadata: - name: test-gcp-environment -spec: - description: A test GCP environment - projectId: test-project diff --git a/kubernetes/hello-workload/hello-workload.k.yaml b/kubernetes/hello-workload/hello-workload.k.yaml index 7662110..38b4695 100644 --- a/kubernetes/hello-workload/hello-workload.k.yaml +++ b/kubernetes/hello-workload/hello-workload.k.yaml @@ -22,7 +22,7 @@ spec: condition: type: Deployment name: Workload Deployment - + - label: create_service ref: kind: ResourceFunction