## Project egress-proxy ```bash PROJECT_ID=egress-proxy # 1. Create the service account gcloud iam service-accounts create proxy-operator \ --project ${PROJECT_ID} \ --display-name "egress-proxies-operator" # Output: # Created service account [proxy-operator]. # Service account email: proxy-operator@egress-proxy.iam.gserviceaccount.com # 2. Grant compute.instanceAdmin.v1 on the project gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member "serviceAccount:proxy-operator@${PROJECT_ID}.iam.gserviceaccount.com" \ --role roles/compute.instanceAdmin.v1 # Output: # --------- # Updated IAM policy for project [egress-proxy]. # bindings: # - members: # - serviceAccount:proxy-operator@egress-proxy.iam.gserviceaccount.com # role: roles/compute.instanceAdmin.v1 # - members: # - serviceAccount:541231138892@cloudservices.gserviceaccount.com # role: roles/compute.instanceGroupManagerServiceAgent # - members: # - serviceAccount:service-541231138892@compute-system.iam.gserviceaccount.com # role: roles/compute.serviceAgent # - members: # - user:admin@fujultimate.cz # role: roles/owner # etag: BwZYuFXko24= # version: 1 # 3. Create the JSON key (this is what goes into the Secret) SA_KEY_PATH=sa_key.json gcloud iam service-accounts keys create $SA_KEY_PATH \ --iam-account proxy-operator@${PROJECT_ID}.iam.gserviceaccount.com # output: # created key [fdff85174a8e80bbd684e76c4d9fe28e2f4b2ddf] of type [json] as [sa_key.json] for [proxy-operator@egress-proxy.iam.gserviceaccount.com] # 4. A **firewall rule**: created VMs get network tag `proxy-operator` (the # default; configurable as `gcp.networkTag`), an ephemeral external IP, # and Squid listening on 3128. gcloud compute firewall-rules create allow-proxy-operator \ --project $PROJECT_ID \ --network default \ --allow tcp:3128 \ --target-tags proxy-operator \ --source-ranges 94.230.145.216/32 ``` ## Phase 2 - resources in kube ```bash SA_KEY_PATH=sa_key.json kubectl -n egress-proxies-operator-system create secret generic gcp-credentials \ --from-file=key.json=$SA_KEY_PATH ``` ## Appendix - full manifests ```bash # crawl CR kubectl apply -f - <<'EOF' apiVersion: crawl.example.com/v1alpha1 kind: Proxy metadata: name: proxy-gcp-sample spec: mode: Managed provider: gcp-eu # must match a provider NAME in providers.yaml placement: zone: europe-west1-b machineType: e2-micro # debian-cloud images have no cloud-init, so spec.cloudInit (passed as # user-data metadata) would be silently ignored there. Ubuntu images do. image: projects/ubuntu-os-cloud/global/images/family/ubuntu-2404-lts-amd64 port: 3128 cloudInit: inline: | #cloud-config package_update: true packages: - squid write_files: - path: /etc/squid/conf.d/proxy-operator.conf content: | http_access allow all via off forwarded_for off runcmd: - systemctl restart squid attributes: geo: eu purpose: crawl EOF # configmap kubectl apply -f - <<'EOF' apiVersion: v1 data: providers.yaml: | providers: - name: kubernetes type: kubernetes - name: gcp-eu # spec.provider on a Proxy refers to this NAME, not the type type: gcp gcp: project: egress-proxy # network: default # these three default as shown # networkTag: proxy-operator # diskSizeGb: 10 kind: ConfigMap metadata: labels: app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: egress-proxies-operator name: egress-proxies-operator-providers-config namespace: egress-proxies-operator-system EOF # operator deployment kubectl apply -f - <<'EOF' apiVersion: apps/v1 kind: Deployment metadata: annotations: deployment.kubernetes.io/revision: "2" labels: app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: egress-proxies-operator control-plane: controller-manager name: egress-proxies-operator-controller-manager namespace: egress-proxies-operator-system spec: progressDeadlineSeconds: 600 replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app.kubernetes.io/name: egress-proxies-operator control-plane: controller-manager strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: annotations: kubectl.kubernetes.io/default-container: manager labels: app.kubernetes.io/name: egress-proxies-operator control-plane: controller-manager spec: containers: - args: - --metrics-bind-address=:8443 - --leader-elect - --health-probe-bind-address=:8081 - --providers-config=/etc/proxy-operator/providers.yaml command: - /manager env: - name: DISCOVERY_TOKEN valueFrom: secretKeyRef: key: token name: discovery-token optional: true - name: GOOGLE_APPLICATION_CREDENTIALS value: /var/secrets/gcp/key.json image: egress-proxies-operator:dev imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 3 httpGet: path: /healthz port: 8081 scheme: HTTP initialDelaySeconds: 15 periodSeconds: 20 successThreshold: 1 timeoutSeconds: 1 name: manager ports: - containerPort: 8081 name: health protocol: TCP - containerPort: 8090 name: discovery protocol: TCP readinessProbe: failureThreshold: 3 httpGet: path: /readyz port: 8081 scheme: HTTP initialDelaySeconds: 5 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 resources: limits: cpu: 500m memory: 128Mi requests: cpu: 10m memory: 64Mi securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL readOnlyRootFilesystem: true terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /etc/proxy-operator name: providers-config readOnly: true - mountPath: /var/secrets/gcp name: gcp-credentials readOnly: true dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault serviceAccount: egress-proxies-operator-controller-manager serviceAccountName: egress-proxies-operator-controller-manager terminationGracePeriodSeconds: 10 volumes: - configMap: defaultMode: 420 name: egress-proxies-operator-providers-config name: providers-config - name: gcp-credentials secret: defaultMode: 420 secretName: gcp-credentials EOF ```