├── deploy ├── crossplane-core │ ├── crossplane-system-namespace.yaml │ ├── crossplane-repository.yaml │ ├── kustomization.yaml │ └── crossplane-release.yaml ├── crossplane-xr │ ├── kustomization.yaml │ └── eks-cluster-xr.yaml ├── crossplane-aws-provider │ ├── kustomization.yaml │ ├── aws-provider.yaml │ └── sealed-secrets-controller.yaml ├── crossplane-composition │ ├── kustomization.yaml │ ├── aws-providerconfig.yaml │ ├── crossplane-eks-composition.yaml │ └── aws-credentials-sealed.yaml ├── monitoring │ ├── prometheus-repository.yaml │ ├── kustomizeconfig.yaml │ ├── kustomization.yaml │ ├── prometheus-release.yaml │ └── prometheus-values.yaml └── webapp │ └── deployment-webapp.yaml ├── images ├── Component-Relationship.png └── Deployment-Architecture.png ├── crossplane-imperative ├── aws-provider.yaml ├── eks-configuration │ ├── crossplane.yaml │ ├── compositeresourcedefinition.yaml │ └── composition.yaml ├── aws-providerconfig.yaml └── eks-cluster-xr.yaml ├── CODE_OF_CONDUCT.md ├── crossplane ├── crossplane-composite-resources.yaml ├── crossplane-configuration-package.yaml ├── crossplane-provider-package.yaml └── crossplane-helmrelease.yaml ├── applications ├── application-webapp.yaml └── application-prometheus.yaml ├── LICENSE ├── remote ├── remote-cluster-setup.md └── service-account-rbac.yaml ├── CONTRIBUTING.md ├── README.md ├── flux.md ├── crossplane.sh └── Grafana-Metrics-Dashboard.json /deploy/crossplane-core/crossplane-system-namespace.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: crossplane-system -------------------------------------------------------------------------------- /images/Component-Relationship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/eks-gitops-crossplane-flux/HEAD/images/Component-Relationship.png -------------------------------------------------------------------------------- /images/Deployment-Architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/eks-gitops-crossplane-flux/HEAD/images/Deployment-Architecture.png -------------------------------------------------------------------------------- /deploy/crossplane-xr/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kustomize.config.k8s.io/v1beta1 3 | kind: Kustomization 4 | resources: 5 | - eks-cluster-xr.yaml 6 | 7 | 8 | -------------------------------------------------------------------------------- /deploy/crossplane-aws-provider/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kustomize.config.k8s.io/v1beta1 3 | kind: Kustomization 4 | resources: 5 | - sealed-secrets-controller.yaml 6 | - aws-provider.yaml 7 | 8 | 9 | -------------------------------------------------------------------------------- /crossplane-imperative/aws-provider.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: pkg.crossplane.io/v1 2 | kind: Provider 3 | metadata: 4 | name: crossplane-provider-aws 5 | spec: 6 | package: "public.ecr.aws/awsvijisarathy/crossplane-provider-aws:v0.23.0" -------------------------------------------------------------------------------- /deploy/crossplane-aws-provider/aws-provider.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: pkg.crossplane.io/v1 3 | kind: Provider 4 | metadata: 5 | name: crossplane-provider-aws 6 | spec: 7 | package: "public.ecr.aws/awsvijisarathy/crossplane-provider-aws:v0.23.0" -------------------------------------------------------------------------------- /deploy/crossplane-composition/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kustomize.config.k8s.io/v1beta1 3 | kind: Kustomization 4 | resources: 5 | - aws-credentials-sealed.yaml 6 | - aws-providerconfig.yaml 7 | - crossplane-eks-composition.yaml 8 | 9 | 10 | -------------------------------------------------------------------------------- /deploy/crossplane-core/crossplane-repository.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: source.toolkit.fluxcd.io/v1beta1 3 | kind: HelmRepository 4 | metadata: 5 | name: crossplane-repository 6 | namespace: crossplane-system 7 | spec: 8 | interval: 5m 9 | url: https://charts.crossplane.io/stable -------------------------------------------------------------------------------- /deploy/crossplane-core/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kustomize.config.k8s.io/v1beta1 3 | kind: Kustomization 4 | namespace: crossplane-system 5 | resources: 6 | - crossplane-system-namespace.yaml 7 | - crossplane-repository.yaml 8 | - crossplane-release.yaml 9 | 10 | -------------------------------------------------------------------------------- /deploy/monitoring/prometheus-repository.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: source.toolkit.fluxcd.io/v1beta1 3 | kind: HelmRepository 4 | metadata: 5 | name: prometheus-community 6 | namespace: flux-system 7 | spec: 8 | interval: 5m 9 | url: https://prometheus-community.github.io/helm-charts 10 | 11 | 12 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /deploy/crossplane-composition/aws-providerconfig.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: aws.crossplane.io/v1beta1 3 | kind: ProviderConfig 4 | metadata: 5 | name: default 6 | spec: 7 | credentials: 8 | source: Secret 9 | secretRef: 10 | namespace: crossplane-system 11 | name: aws-credentials 12 | key: credentials 13 | -------------------------------------------------------------------------------- /crossplane-imperative/eks-configuration/crossplane.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: meta.pkg.crossplane.io/v1alpha1 2 | kind: Configuration 3 | metadata: 4 | name: eks-cluster-composition 5 | annotations: 6 | provider: aws 7 | spec: 8 | crossplane: 9 | version: ">=v1.0.0" 10 | dependsOn: 11 | - provider: public.ecr.aws/awsvijisarathy/crossplane-provider-aws 12 | version: ">=v0.14.0" 13 | -------------------------------------------------------------------------------- /deploy/crossplane-composition/crossplane-eks-composition.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: pkg.crossplane.io/v1 2 | kind: Configuration 3 | metadata: 4 | name: crossplane-eks-composition 5 | spec: 6 | ignoreCrossplaneConstraints: false 7 | package: public.ecr.aws/awsvijisarathy/crossplane-eks-composition:7.0.0 8 | packagePullPolicy: IfNotPresent 9 | revisionActivationPolicy: Automatic 10 | revisionHistoryLimit: 0 11 | skipDependencyResolution: false 12 | -------------------------------------------------------------------------------- /crossplane/crossplane-composite-resources.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 3 | kind: Kustomization 4 | metadata: 5 | name: crossplane-resources 6 | namespace: flux-system 7 | spec: 8 | dependsOn: 9 | - name: crossplane-configuration-package 10 | interval: 30s 11 | path: ./deploy/crossplane-xr 12 | prune: true 13 | sourceRef: 14 | kind: GitRepository 15 | name: flux-system 16 | validation: client 17 | 18 | -------------------------------------------------------------------------------- /deploy/crossplane-composition/aws-credentials-sealed.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: bitnami.com/v1alpha1 2 | kind: SealedSecret 3 | metadata: 4 | creationTimestamp: null 5 | name: aws-credentials 6 | namespace: crossplane-system 7 | spec: 8 | encryptedData: 9 | credentials: XXXXXXXXXXXXXX 10 | template: 11 | data: null 12 | metadata: 13 | creationTimestamp: null 14 | name: aws-credentials 15 | namespace: crossplane-system 16 | 17 | -------------------------------------------------------------------------------- /applications/application-webapp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 3 | kind: Kustomization 4 | metadata: 5 | name: application-webapp 6 | namespace: flux-system 7 | spec: 8 | interval: 30s 9 | path: ./deploy/webapp 10 | prune: true 11 | sourceRef: 12 | kind: GitRepository 13 | name: flux-system 14 | kubeConfig: 15 | secretRef: 16 | name: crossplane-workload-cluster-connection 17 | validation: client 18 | -------------------------------------------------------------------------------- /crossplane/crossplane-configuration-package.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 3 | kind: Kustomization 4 | metadata: 5 | name: crossplane-configuration-package 6 | namespace: flux-system 7 | spec: 8 | dependsOn: 9 | - name: crossplane-provider-package 10 | interval: 30s 11 | path: ./deploy/crossplane-composition 12 | prune: true 13 | sourceRef: 14 | kind: GitRepository 15 | name: flux-system 16 | validation: client 17 | 18 | -------------------------------------------------------------------------------- /deploy/crossplane-core/crossplane-release.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: helm.toolkit.fluxcd.io/v2beta1 2 | kind: HelmRelease 3 | metadata: 4 | name: crossplane-core 5 | namespace: flux-system 6 | spec: 7 | releaseName: crossplane-core 8 | interval: 5m 9 | chart: 10 | spec: 11 | chart: crossplane 12 | version: '1.6.2' 13 | sourceRef: 14 | kind: HelmRepository 15 | name: crossplane-repository 16 | namespace: crossplane-system 17 | interval: 1m 18 | 19 | 20 | -------------------------------------------------------------------------------- /deploy/monitoring/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # It is possible to use Kustomize ConfigMap generator to trigger a Helm release upgrade every time the encoded values change. 3 | # First, create a kustomizeconfig.yaml for Kustomize to be able to patch ConfigMap referenced in HelmRelease manifest 4 | # The 'fieldSpecs/path' identifies the ConfigMap referenced in the HelmRelease. 5 | # Create a HelmRelease definition that references a ConfigMap 6 | # Create a 'kustomization.yaml' that generates the ConfigMap using the configurations from 'kustomizeconfig.yaml' 7 | # 8 | nameReference: 9 | - kind: ConfigMap 10 | version: v1 11 | fieldSpecs: 12 | - path: spec/valuesFrom/name 13 | kind: HelmRelease 14 | 15 | -------------------------------------------------------------------------------- /crossplane/crossplane-provider-package.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 3 | kind: Kustomization 4 | metadata: 5 | name: crossplane-provider-package 6 | namespace: flux-system 7 | spec: 8 | dependsOn: 9 | - name: crossplane-helmrelease 10 | interval: 30s 11 | path: ./deploy/crossplane-aws-provider 12 | prune: true 13 | sourceRef: 14 | kind: GitRepository 15 | name: flux-system 16 | healthChecks: 17 | - kind: Deployment 18 | name: sealed-secrets-controller 19 | namespace: sealed-secrets 20 | - kind: Deployment 21 | name: crossplane-provider-aws-45985ebe751d 22 | namespace: crossplane-system 23 | validation: client 24 | timeout: 2m 25 | 26 | -------------------------------------------------------------------------------- /applications/application-prometheus.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 3 | kind: Kustomization 4 | metadata: 5 | name: application-prometheus 6 | namespace: flux-system 7 | spec: 8 | dependsOn: 9 | - name: application-webapp 10 | interval: 30s 11 | path: ./deploy/monitoring 12 | prune: true 13 | sourceRef: 14 | kind: GitRepository 15 | name: flux-system 16 | healthChecks: 17 | - apiVersion: helm.toolkit.fluxcd.io/v2beta1 18 | kind: HelmRelease 19 | name: prometheus-helmrelease 20 | namespace: flux-system 21 | # 22 | # Prometheus is deployed using a HelmRelease. 23 | # Hence, the 'kubeConfig' field that points to the remote workload cluster is set in the HelmRelease manifest 24 | # 25 | validation: client 26 | timeout: 2m 27 | 28 | -------------------------------------------------------------------------------- /deploy/monitoring/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kustomize.config.k8s.io/v1beta1 3 | kind: Kustomization 4 | resources: 5 | - prometheus-repository.yaml 6 | - prometheus-release.yaml 7 | # 8 | # Generate a ConfigMap resources from the specified file 9 | # This will generate a ConfigMap which will contain a key named 'value.yaml' 10 | # The value associated with this key will be the contents of the file 'prometheus-nosidecar-values.yaml' 11 | # This ConfigMap can then be references in a HelmRelease to override the default values for a Helm chart 12 | # 13 | configMapGenerator: 14 | - name: prometheus-configmap 15 | namespace: flux-system 16 | files: 17 | - values.yaml=prometheus-values.yaml 18 | # 19 | # Trigger a Helm release upgrade everytime the values in prometheus-values.yaml change 20 | # 21 | configurations: 22 | - kustomizeconfig.yaml 23 | 24 | -------------------------------------------------------------------------------- /crossplane-imperative/aws-providerconfig.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: aws.crossplane.io/v1beta1 2 | kind: ProviderConfig 3 | metadata: 4 | # 5 | # In order to authenticate with the AWS API, the provider controllers need to have access to credentials. It could be an IAM User for AWS 6 | # Note that every Crossplane managed resource has a 'providerConfig' field which allows us to specify a separate ProviderConfig per Managed Resource. 7 | # This allows us to use IAM credentials that are limited in scope to perform the operations related to only that managed resource. 8 | # If 'providerConfigRef' is not specified for a Managed Resource, Crossplane will attempt to use a ProviderConfig named 'default' 9 | # 10 | name: default 11 | spec: 12 | credentials: 13 | source: Secret 14 | secretRef: 15 | namespace: crossplane-system 16 | name: aws-credentials 17 | key: credentials 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /deploy/monitoring/prometheus-release.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: helm.toolkit.fluxcd.io/v2beta1 3 | kind: HelmRelease 4 | # 5 | # Note that this HelmRelease is deployed on the workload cluster 6 | # The release itself is made in a namespace that equals to the namespace of the HelmRelease which is 'flux-system' here. 7 | # As this namespace should already exist, we have to create a 'flux-system' namespace on the workload cluster. 8 | # 9 | metadata: 10 | name: prometheus-helmrelease 11 | namespace: flux-system 12 | spec: 13 | # install: 14 | # createNamespace: true 15 | targetNamespace: monitoring 16 | releaseName: prometheus-for-amp 17 | interval: 5m 18 | kubeConfig: 19 | secretRef: 20 | name: crossplane-workload-cluster-connection 21 | chart: 22 | spec: 23 | chart: prometheus 24 | sourceRef: 25 | kind: HelmRepository 26 | name: prometheus-community 27 | namespace: flux-system 28 | interval: 1m 29 | valuesFrom: 30 | - kind: ConfigMap 31 | name: prometheus-configmap 32 | 33 | 34 | -------------------------------------------------------------------------------- /deploy/monitoring/prometheus-values.yaml: -------------------------------------------------------------------------------- 1 | serviceAccounts: 2 | server: 3 | name: prometheus-service-account 4 | annotations: 5 | # 6 | # Set this to the ARN of an IAM role for the service account. 7 | # For details, refer to the documentation here: https://docs.aws.amazon.com/prometheus/latest/userguide/set-up-irsa.html 8 | # 9 | eks.amazonaws.com/role-arn: XXXXXXXXXX 10 | 11 | nodeExporter: 12 | enabled: false 13 | alertmanager: 14 | enabled: false 15 | pushgateway: 16 | enabled: false 17 | kubeStateMetrics: 18 | enabled: false 19 | 20 | server: 21 | statefulSet: 22 | enabled: false 23 | persistentVolume: 24 | enabled: false 25 | 26 | remoteWrite: 27 | # 28 | # Set the ID of an AMP workspace 29 | # 30 | - url: https://aps-workspaces.us-west-2.amazonaws.com/workspaces/XXXXXXXXXXXXX/api/v1/remote_write 31 | sigv4: 32 | region: us-west-2 33 | queue_config: 34 | max_samples_per_send: 1000 35 | max_shards: 200 36 | capacity: 2500 -------------------------------------------------------------------------------- /crossplane/crossplane-helmrelease.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 3 | kind: Kustomization 4 | metadata: 5 | name: crossplane-helmrelease 6 | namespace: flux-system 7 | spec: 8 | interval: 30s 9 | path: ./deploy/crossplane-core 10 | prune: true 11 | sourceRef: 12 | kind: GitRepository 13 | name: flux-system 14 | # 15 | # A Kustomization can contain a series of health checks used to determine the rollout status of the deployed workloads and the ready status of custom resources. 16 | # A health check entry can reference either one of the Kubernetes builtin types or GitOps Toolkit types such as HelmRelease, HelmRepository, GitRepository, etc. 17 | # When a Kustomization contains HelmRelease objects, instead of checking the underling Deployments, you can define a health check that waits for the HelmReleases to be reconciled with 18 | # 19 | healthChecks: 20 | - apiVersion: helm.toolkit.fluxcd.io/v2beta1 21 | kind: HelmRelease 22 | name: crossplane-core 23 | namespace: crossplane-system 24 | - kind: Deployment 25 | name: crossplane 26 | namespace: crossplane-system 27 | - kind: Deployment 28 | name: crossplane-rbac-manager 29 | namespace: crossplane-system 30 | validation: client 31 | timeout: 2m 32 | 33 | -------------------------------------------------------------------------------- /crossplane-imperative/eks-cluster-xr.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: eks.sarathy.io/v1beta1 3 | kind: EKSCluster 4 | metadata: 5 | name: crossplane-cluster 6 | spec: 7 | parameters: 8 | region: us-west-2 9 | vpc-name: "EKS-CROSSPLANE-VPC" 10 | vpc-cidrBlock: "192.168.48.0/20" 11 | 12 | subnet1-public-name: "PUBLIC-WORKER-1" 13 | subnet1-public-cidrBlock: "192.168.48.0/24" 14 | subnet1-public-availabilityZone: "us-west-2a" 15 | 16 | subnet2-public-name: "PUBLIC-WORKER-2" 17 | subnet2-public-cidrBlock: "192.168.49.0/24" 18 | subnet2-public-availabilityZone: "us-west-2b" 19 | 20 | subnet1-private-name: "PRIVATE-WORKER-1" 21 | subnet1-private-cidrBlock: "192.168.50.0/24" 22 | subnet1-private-availabilityZone: "us-west-2a" 23 | 24 | subnet2-private-name: "PRIVATE-WORKER-2" 25 | subnet2-private-cidrBlock: "192.168.51.0/24" 26 | subnet2-private-availabilityZone: "us-west-2b" 27 | 28 | cluster-role: arn:aws:iam::XXXX:role/EKS-Cluster-Role 29 | workernode-role: arn:aws:iam::XXXX:role/EKS-WorkerNode-Role 30 | 31 | k8s-version: "1.21" 32 | workload-type: "non-gpu" 33 | workers-size: 2 34 | 35 | compositionRef: 36 | name: amazon-eks-cluster 37 | 38 | writeConnectionSecretToRef: 39 | namespace: flux-system 40 | name: crossplane-cluster-connection -------------------------------------------------------------------------------- /deploy/crossplane-xr/eks-cluster-xr.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: eks.sarathy.io/v1beta1 3 | kind: EKSCluster 4 | metadata: 5 | name: crossplane-flux-cluster 6 | spec: 7 | parameters: 8 | region: us-west-2 9 | vpc-name: "EKS-CROSSPLANE-FLUX-VPC" 10 | vpc-cidrBlock: "192.168.48.0/20" 11 | 12 | subnet1-public-name: "PUBLIC-WORKER-1 " 13 | subnet1-public-cidrBlock: "192.168.48.0/24" 14 | subnet1-public-availabilityZone: "us-west-2a" 15 | 16 | subnet2-public-name: "PUBLIC-WORKER-2" 17 | subnet2-public-cidrBlock: "192.168.49.0/24" 18 | subnet2-public-availabilityZone: "us-west-2b" 19 | 20 | subnet1-private-name: "PRIVATE-WORKER-1" 21 | subnet1-private-cidrBlock: "192.168.50.0/24" 22 | subnet1-private-availabilityZone: "us-west-2a" 23 | 24 | subnet2-private-name: "PRIVATE-WORKER-2" 25 | subnet2-private-cidrBlock: "192.168.51.0/24" 26 | subnet2-private-availabilityZone: "us-west-2b" 27 | 28 | cluster-role: "arn:aws:iam::XXXXXXXX:role/EKS-Cluster-Role" 29 | workernode-role: "arn:aws:iam::XXXXXXXX:role/EKS-WorkerNode-Role" 30 | 31 | k8s-version: "1.20" 32 | workload-type: "non-gpu" 33 | workers-size: 2 34 | 35 | compositionRef: 36 | name: amazon-eks-cluster 37 | 38 | writeConnectionSecretToRef: 39 | namespace: flux-system 40 | name: crossplane-flux-cluster-connection -------------------------------------------------------------------------------- /deploy/webapp/deployment-webapp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: flux-system 6 | 7 | --- 8 | apiVersion: v1 9 | kind: Namespace 10 | metadata: 11 | name: monitoring 12 | 13 | --- 14 | apiVersion: v1 15 | kind: Namespace 16 | metadata: 17 | name: golang 18 | 19 | --- 20 | apiVersion: apps/v1 21 | kind: Deployment 22 | metadata: 23 | name: webapp 24 | namespace: golang 25 | spec: 26 | replicas: 3 27 | selector: 28 | matchLabels: 29 | app: webapp 30 | role: scrape-target 31 | template: 32 | metadata: 33 | labels: 34 | app: webapp 35 | role: scrape-target 36 | annotations: 37 | prometheus.io/scrape: 'true' 38 | prometheus.io/port: '3000' 39 | prometheus.io/path: '/metrics' 40 | spec: 41 | containers: 42 | - name: golang 43 | image: public.ecr.aws/awsvijisarathy/prometheus-webapp:2.0 44 | imagePullPolicy: Always 45 | resources: 46 | requests: 47 | cpu: "128m" 48 | memory: "128Mi" 49 | ports: 50 | - name: http 51 | containerPort: 3000 52 | protocol: TCP 53 | --- 54 | apiVersion: v1 55 | kind: Service 56 | metadata: 57 | name: webapp-svc 58 | namespace: golang 59 | spec: 60 | sessionAffinity: None 61 | type: ClusterIP 62 | ports: 63 | - port: 80 64 | protocol: TCP 65 | targetPort: 3000 66 | selector: 67 | app: webapp 68 | role: scrape-target 69 | 70 | -------------------------------------------------------------------------------- /remote/remote-cluster-setup.md: -------------------------------------------------------------------------------- 1 | ```shell 2 | # 3 | # After the remote EKS cluster creation is completed using Crossplane, do the following: 4 | # 'kubeconfig-admin' file contains the KubeConfig data created by Crossplane when the remote cluster is provisioned. 5 | # This can be obtained from the Secret 'crossplane-workload-cluster-connection' created in the 'flux-system' namespace by Crossplane. 6 | # These credentials pertain to that of the cluster creator and has system:masters permissions in the EKS cluster and are rorated on a continual basis. 7 | # Using this KubeConfig data, create a service account in the workload cluster 8 | # 9 | kubectl apply -f service-account-rbac.yaml --kubeconfig ./kubeconfig-admin 10 | 11 | # 12 | # After applying the above change, a service account named 'apprunner' is created in the 'applications' namespace of the remote cluster. 13 | # The service account is configured to have 'cluster-admin' permissions in the EKS cluster. 14 | # Next, create a file 'kubeconfig-sa' with the KubeConfig data that pertains to the this service account's credentials. 15 | # These credentials are not rotated and are permanent. 16 | # 17 | cp kubeconfig-admin kubeconfig-sa 18 | SERVICE_ACCOUNT_NAME=apprunner 19 | SERVICE_ACCOUNT_NAMESPACE=applications 20 | SERVICE_ACCOUNT_SECRET_NAME=$(kubectl -n $SERVICE_ACCOUNT_NAMESPACE get sa $SERVICE_ACCOUNT_NAME -o jsonpath='{.secrets[0].name}' --kubeconfig ./kubeconfig-admin) 21 | SERVICE_ACCOUNT_TOKEN=$(kubectl -n $SERVICE_ACCOUNT_NAMESPACE get secret $SERVICE_ACCOUNT_SECRET_NAME -o jsonpath={.data.token} --kubeconfig ./kubeconfig-admin | base64 -d) 22 | kubectl config set-credentials $SERVICE_ACCOUNT_NAME --token=$SERVICE_ACCOUNT_TOKEN --kubeconfig=./kubeconfig-sa 23 | kubectl config set-context --current --user=$SERVICE_ACCOUNT_NAME --kubeconfig=./kubeconfig-sa 24 | 25 | # 26 | # Create a Secret named 'crossplane-workload-cluster-sa-connection' in the 'flux-system' namespace 27 | # Reference this Secret in Kustomization/HelmRelease that are targeting deployments to the workload cluster 28 | # 29 | kubectl -n flux-system create secret generic crossplane-workload-cluster-sa-connection --from-file=value=./kubeconfig-sa 30 | ``` -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Amazon EKS cluser management with Crossplane and Flux 2 | 3 | This Git repository contains software artifacts to deploy [Crossplane](https://crossplane.io/) server and [Flux](https://fluxcd.io/) to an existing Amazon EKS cluster and then leverage the GitOps workflow to manage both provisioning a remote EKS cluster with Crossplane and subsequently manage application deployments to it using Flux. Please refer to the [accompanying blog post](https://aws.amazon.com/blogs/containers/gitops-model-for-provisioning-and-bootstrapping-amazon-eks-clusters-using-crossplane-and-flux) for details about how this works. Please also refer to the [earlier blog in this series](https://aws.amazon.com/blogs/containers/gitops-model-for-provisioning-and-bootstrapping-amazon-eks-clusters-using-crossplane-and-argo-cd/) for additional context. 4 | 5 | Deployment architecture 6 | 7 | ### Solution overview 8 | 9 | Here’s the high level overview of the solution architecture. 10 | 11 | - Start off with an Amazon EKS cluster that was created using any one of the approaches outlined [here](https://docs.aws.amazon.com/eks/latest/userguide/create-cluster.html). 12 | - Install and bootstrap Flux on this cluster to manage all deployment tasks, pointing to a Git repository containing the deployment artifacts. 13 | - Deploy Crossplane components needed to manage the lifecycle of AWS managed service resources. 14 | - Deploy Crossplane composite resource to provision an Amazon EKS cluster 15 | - Deploy a set of workloads to the new cluster 16 | 17 | The goal is to manage all of these tasks in a declarative style based on the [GitOps](https://www.weave.works/blog/what-is-gitops-really) approach. 18 | 19 | ### Deployment overview 20 | 21 | #### Imperative approach 22 | The script [crossplane.sh](https://github.com/aws-samples/eks-gitops-crossplane-flux/blob/main/crossplane.sh) outlines the CLI commands to install Crossplane to a management EKS cluster and then provision a workload EKS cluster. The implementation uses Crossplane's [Composition](https://crossplane.io/docs/v1.4/concepts/composition.html) and [CompositeResourceDefinition](https://crossplane.io/docs/v1.4/concepts/composition.html) to create a Crossplane [Configuration package](https://crossplane.io/docs/v1.4/concepts/packages.html#configuration-packages) that will provision the complete infrastructure for setting up an EKS cluster - VPC, subnets, internet gateway, NAT gateways, route tables, and the EKS cluster with a managed node group. The figure below shows the relationship between various Crossplane custom resources used in this Configuration package and the set of AWS managed resources that they provision. 23 | 24 | Component Relationship 25 | 26 | #### Declarative approach 27 | The script [flux.sh](https://github.com/aws-samples/eks-gitops-crossplane-flux/blob/main/flux.sh) outlines the steps involved in installing and bootstrapping Flux on the management EKS cluster and then leveraging the GitOps workflow in Flux to manage both provisioning and management of a remote workload cluster. 28 | 29 | ## Security 30 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 31 | 32 | ## License 33 | This library is licensed under the MIT-0 License. See the LICENSE file. -------------------------------------------------------------------------------- /remote/service-account-rbac.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: applications 6 | 7 | --- 8 | apiVersion: v1 9 | kind: ServiceAccount 10 | metadata: 11 | name: apprunner 12 | namespace: applications 13 | 14 | # 15 | # When Flux reconciles a HelmRelease to a remote cluster, the list of Helm releases are created in the flux-system. 16 | # TO facilitate this, the 'apprunner' service account is granted full access to the 'flux-system' namespace in the workload cluster. 17 | # The actual application workloads that makeup the chart are deployed into the namespace specified by the 'targetNamespace' field in the HelmRelease resource. 18 | # 19 | --- 20 | apiVersion: v1 21 | kind: Namespace 22 | metadata: 23 | name: flux-system 24 | 25 | --- 26 | apiVersion: rbac.authorization.k8s.io/v1 27 | kind: RoleBinding 28 | metadata: 29 | name: apprunner-rolebinding 30 | namespace: flux-system 31 | roleRef: 32 | apiGroup: rbac.authorization.k8s.io 33 | kind: ClusterRole 34 | name: cluster-admin 35 | subjects: 36 | - kind: ServiceAccount 37 | name: apprunner 38 | namespace: applications 39 | 40 | --- 41 | apiVersion: v1 42 | kind: Namespace 43 | metadata: 44 | name: golang 45 | 46 | --- 47 | apiVersion: rbac.authorization.k8s.io/v1 48 | kind: RoleBinding 49 | metadata: 50 | name: apprunner-rolebinding 51 | namespace: golang 52 | roleRef: 53 | apiGroup: rbac.authorization.k8s.io 54 | kind: ClusterRole 55 | name: cluster-admin 56 | subjects: 57 | - kind: ServiceAccount 58 | name: apprunner 59 | namespace: applications 60 | 61 | --- 62 | apiVersion: v1 63 | kind: Namespace 64 | metadata: 65 | name: monitoring 66 | 67 | --- 68 | apiVersion: rbac.authorization.k8s.io/v1 69 | kind: RoleBinding 70 | metadata: 71 | name: apprunner-rolebinding 72 | namespace: monitoring 73 | roleRef: 74 | apiGroup: rbac.authorization.k8s.io 75 | kind: ClusterRole 76 | name: cluster-admin 77 | subjects: 78 | - kind: ServiceAccount 79 | name: apprunner 80 | namespace: applications 81 | 82 | # 83 | # When Prometheus server is deployed using the prometheus-community Helm chart it creates a ClusterRole that grants permission to [get,list,watch] resources in the core API group. 84 | # Therefore, the 'apprunner' service account should be able to create ClusterRoles and ClusterRoleBindings that can grant these permissions to a Kubernetes subject. 85 | # In order to facilitate this, the ClusterRole below is created and bound to the 'apprunner' service account 86 | # 87 | --- 88 | apiVersion: rbac.authorization.k8s.io/v1 89 | kind: ClusterRole 90 | metadata: 91 | name: apprunner-role 92 | rules: 93 | - apiGroups: 94 | - rbac.authorization.k8s.io 95 | resources: 96 | - clusterrolebindings 97 | verbs: 98 | - get 99 | - list 100 | - watch 101 | - create 102 | - apiGroups: 103 | - rbac.authorization.k8s.io 104 | resources: 105 | - clusterroles 106 | verbs: 107 | - get 108 | - list 109 | - watch 110 | - create 111 | - bind 112 | - apiGroups: 113 | - "" 114 | resources: 115 | - nodes 116 | - nodes/proxy 117 | - nodes/metrics 118 | - services 119 | - endpoints 120 | - pods 121 | - ingresses 122 | - configmaps 123 | verbs: 124 | - get 125 | - list 126 | - watch 127 | - apiGroups: 128 | - extensions 129 | - networking.k8s.io 130 | resources: 131 | - ingresses/status 132 | - ingresses 133 | verbs: 134 | - get 135 | - list 136 | - watch 137 | - nonResourceURLs: 138 | - /metrics 139 | verbs: 140 | - get 141 | 142 | --- 143 | apiVersion: rbac.authorization.k8s.io/v1 144 | kind: ClusterRoleBinding 145 | metadata: 146 | name: apprunner-clusterrolebinding 147 | roleRef: 148 | apiGroup: rbac.authorization.k8s.io 149 | kind: ClusterRole 150 | name: apprunner-role 151 | subjects: 152 | - kind: ServiceAccount 153 | name: apprunner 154 | namespace: applications -------------------------------------------------------------------------------- /flux.md: -------------------------------------------------------------------------------- 1 | ```shell 2 | # 3 | # Set these environment variables 4 | # 5 | export CLUSTER_NAME=XXXX 6 | export GITHUB_TOKEN=XXXXX 7 | export GITHUB_USER=XXXX 8 | 9 | # 10 | # Bootstrapping the cluster with Flux 11 | # The bootstrap process will automatically create a GitRepository custom resource that points to the given repository 12 | # The GitRepository resource is named after the namespace where Flux GitOps ToolKit is installed. In this case, it is 'flux-system' 13 | # The bootstrap process will configure the repository with an SSH key for read-only access 14 | # 15 | kubectl create ns flux-system 16 | flux bootstrap github \ 17 | --components-extra=image-reflector-controller,image-automation-controller \ 18 | --owner=$GITHUB_USER \ 19 | --namespace=flux-system \ 20 | --repository=eks-gitops-crossplane-flux \ 21 | --branch=main \ 22 | --path=clusters/$CLUSTER_NAME \ 23 | --personal 24 | 25 | # 26 | # In order to authenticate with the external provider API such as AWS, the Crossplane AWS provider controller need to have access to credentials. 27 | # An AWS user with Administrative privileges is needed to enable Crossplane to create the required resources 28 | # We wil have to first create a configuration file, secrets.conf, with credeantials of an AWS account in the following format. 29 | # 30 | # [default] 31 | # aws_access_key_id = XXXXXXXXXXXXXXXXXXXXXXX 32 | # aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXX 33 | # 34 | # Then using this file, a YAML file that defines a Kubernetes Secret is created as follows 35 | # 36 | kubectl -n crossplane-system create secret generic aws-credentials --from-file=credentials=./secrets.conf --dry-run=client -o yaml > aws-credentials.yaml 37 | 38 | # 39 | # Next, deploy the Bitnami's Sealed Secrets controller in the 'sealed-secrets' namespace 40 | # Then, generate a SealedSecret corresponding to the 'aws-credentials' Secret created above. This is done as shown below using the 'kubeseal' companion utility for Bitnami's Sealed Secrets. 41 | # The file 'aws-credentials-sealed.yaml' resulting from the operation below is the one to deploy to the management cluster in the GitOps workflow. 42 | # Push this file to the './deploy/crossplane-composition' directory of the GitHub repo that Flux is pointing to 43 | # 44 | kubeseal --controller-namespace sealed-secrets --format yaml < aws-credentials.yaml > aws-credentials-sealed.yaml 45 | 46 | # 47 | # Important! Extract the master sealing key from the Sealed Secrets controller into a YAML file. 48 | # After extracting the master key, the Sealed Secrets controller may be termintaed. 49 | # The controller per se will get deployed as part of the GitOps workflow. 50 | # But you must make sure that the sealing key is first deployed using this file so that all SealedSecrets that were created using this master could be unsealed 51 | # 52 | kubectl get secret -n sealed-secrets -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml > sealing-master.yaml 53 | 54 | 55 | # 56 | # Now, you are ready to initiate the GitOps worflow. 57 | # Create a Kustomization resource under 'cluster/$CLUSTER_NAME' that points to the 'crossplane' directory in the config repo. 58 | # Pushing this file to the Git repository will trigger a Flux reconcilliation loop which will install the following: 59 | # 1. Crossplane core components 60 | # 2. Crossplane AWS provider-specific components 61 | # 3. Crossplane Configuration package for creating EKS cluster and other AWS resources 62 | # 4. Composite resource to create an EKS cluster 63 | # When this reconcilliation loop is completed, Crossplane will start provisioning the EKS cluster. 64 | # It will take about 10 minutes for the cluster to be ready and operational 65 | # 66 | mkdir -p ./clusters/${CLUSTER_NAME} 67 | flux create kustomization crossplane \ 68 | --source=flux-system \ 69 | --namespace=flux-system \ 70 | --path=./crossplane \ 71 | --prune=true \ 72 | --validation=client \ 73 | --interval=30s \ 74 | --export > ./clusters/$CLUSTER_NAME/crossplane.yaml 75 | 76 | # 77 | # To deploy workloads to the remote cluster using the credentials of the cluster creator, continue with the following step. 78 | # To deploy using the credentials of a service account with appropriate set of RBAC permissions, refer to ./remote/remote-cluster-setup.sh before proceeding further. 79 | # Create a Kustomization resource under 'cluster/$CLUSTER_NAME' that points to the 'applications' directory 80 | # Pushing this file to the Git repository will trigger a Flux reconcilliation loop which will install the following: 81 | # 1. Sample web application that exposes Prometheus metrics 82 | # 2. Prometheus server which scrapes the metrics from the sample application and sends it to an AMP workspace 83 | # 84 | mkdir -p ./clusters/${CLUSTER_NAME} 85 | flux create kustomization applications \ 86 | --source=flux-system \ 87 | --namespace=flux-system \ 88 | --path=./applications \ 89 | --prune=true \ 90 | --validation=client \ 91 | --interval=30s \ 92 | --export > ./clusters/$CLUSTER_NAME/applications.yaml 93 | 94 | 95 | ``` 96 | -------------------------------------------------------------------------------- /crossplane-imperative/eks-configuration/compositeresourcedefinition.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.crossplane.io/v1 3 | kind: CompositeResourceDefinition 4 | metadata: 5 | name: eksclusters.eks.sarathy.io 6 | spec: 7 | group: eks.sarathy.io 8 | names: 9 | kind: EKSCluster 10 | plural: eksclusters 11 | connectionSecretKeys: 12 | - cluster-ca 13 | - apiserver-endpoint 14 | - value 15 | versions: 16 | - name: v1beta1 17 | served: true 18 | referenceable: true 19 | schema: 20 | openAPIV3Schema: 21 | type: object 22 | properties: 23 | spec: 24 | type: object 25 | properties: 26 | parameters: 27 | type: object 28 | properties: 29 | region: 30 | description: Geographic location of this VPC 31 | type: string 32 | enum: ["us-east-1", "us-west-2"] 33 | 34 | vpc-cidrBlock: 35 | description: CIDR block for VPC 36 | type: string 37 | vpc-name: 38 | description: Name for VPC 39 | type: string 40 | 41 | subnet1-public-name: 42 | description: Name for public subnet 1 43 | type: string 44 | subnet1-public-cidrBlock: 45 | description: CIDR block for public subnet 1 46 | type: string 47 | subnet1-public-availabilityZone: 48 | description: AZ for public subnet 1 49 | type: string 50 | 51 | subnet2-public-name: 52 | description: Name for public subnet 2 53 | type: string 54 | subnet2-public-cidrBlock: 55 | description: CIDR block for public subnet 2 56 | type: string 57 | subnet2-public-availabilityZone: 58 | description: AZ for public subnet 2 59 | type: string 60 | 61 | subnet1-private-name: 62 | description: Name for private subnet 1 63 | type: string 64 | subnet1-private-cidrBlock: 65 | description: CIDR block for private subnet 1 66 | type: string 67 | subnet1-private-availabilityZone: 68 | description: AZ for private subnet 1 69 | type: string 70 | 71 | subnet2-private-name: 72 | description: Name for private subnet 2 73 | type: string 74 | subnet2-private-cidrBlock: 75 | description: CIDR block for private subnet 2 76 | type: string 77 | subnet2-private-availabilityZone: 78 | description: AZ for private subnet 2 79 | type: string 80 | 81 | cluster-role: 82 | description: EKS cluster role 83 | type: string 84 | workernode-role: 85 | description: EKS worker node role 86 | type: string 87 | 88 | k8s-version: 89 | description: Kubernetes version 90 | type: string 91 | enum: ["1.20", "1.21", "1.22"] 92 | workers-size: 93 | description: Desired number of worker nodes in the cluster 94 | type: integer 95 | workload-type: 96 | description: Type of workloads to be run on this cluster (GPU or non-GPU)" 97 | type: string 98 | enum: ["gpu", "non-gpu"] 99 | 100 | required: 101 | - region 102 | - vpc-name 103 | - vpc-cidrBlock 104 | - subnet1-public-name 105 | - subnet1-public-cidrBlock 106 | - subnet1-public-availabilityZone 107 | - subnet2-public-name 108 | - subnet2-public-cidrBlock 109 | - subnet2-public-availabilityZone 110 | - subnet1-private-name 111 | - subnet1-private-cidrBlock 112 | - subnet1-private-availabilityZone 113 | - subnet2-private-name 114 | - subnet2-private-cidrBlock 115 | - subnet2-private-availabilityZone 116 | - k8s-version 117 | - workers-size 118 | - workload-type 119 | - cluster-role 120 | - workernode-role 121 | required: 122 | - parameters 123 | -------------------------------------------------------------------------------- /deploy/crossplane-aws-provider/sealed-secrets-controller.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | labels: 6 | name: sealed-secrets-service-proxier 7 | name: sealed-secrets-service-proxier 8 | namespace: sealed-secrets 9 | rules: 10 | - apiGroups: 11 | - "" 12 | resourceNames: 13 | - 'http:sealed-secrets-controller:' 14 | - sealed-secrets-controller 15 | resources: 16 | - services/proxy 17 | verbs: 18 | - create 19 | - get 20 | --- 21 | apiVersion: rbac.authorization.k8s.io/v1 22 | kind: Role 23 | metadata: 24 | labels: 25 | name: sealed-secrets-key-admin 26 | name: sealed-secrets-key-admin 27 | namespace: sealed-secrets 28 | rules: 29 | - apiGroups: 30 | - "" 31 | resources: 32 | - secrets 33 | verbs: 34 | - create 35 | - list 36 | --- 37 | apiVersion: v1 38 | kind: Service 39 | metadata: 40 | labels: 41 | name: sealed-secrets-controller 42 | name: sealed-secrets-controller 43 | namespace: sealed-secrets 44 | spec: 45 | ports: 46 | - port: 8080 47 | targetPort: 8080 48 | selector: 49 | name: sealed-secrets-controller 50 | type: ClusterIP 51 | --- 52 | apiVersion: rbac.authorization.k8s.io/v1 53 | kind: RoleBinding 54 | metadata: 55 | labels: 56 | name: sealed-secrets-service-proxier 57 | name: sealed-secrets-service-proxier 58 | namespace: sealed-secrets 59 | roleRef: 60 | apiGroup: rbac.authorization.k8s.io 61 | kind: Role 62 | name: sealed-secrets-service-proxier 63 | subjects: 64 | - apiGroup: rbac.authorization.k8s.io 65 | kind: Group 66 | name: system:authenticated 67 | --- 68 | apiVersion: apiextensions.k8s.io/v1 69 | kind: CustomResourceDefinition 70 | metadata: 71 | name: sealedsecrets.bitnami.com 72 | spec: 73 | group: bitnami.com 74 | names: 75 | kind: SealedSecret 76 | listKind: SealedSecretList 77 | plural: sealedsecrets 78 | singular: sealedsecret 79 | scope: Namespaced 80 | versions: 81 | - name: v1alpha1 82 | schema: 83 | openAPIV3Schema: 84 | properties: 85 | spec: 86 | type: object 87 | x-kubernetes-preserve-unknown-fields: true 88 | status: 89 | x-kubernetes-preserve-unknown-fields: true 90 | type: object 91 | served: true 92 | storage: true 93 | subresources: 94 | status: {} 95 | --- 96 | apiVersion: rbac.authorization.k8s.io/v1 97 | kind: RoleBinding 98 | metadata: 99 | labels: 100 | name: sealed-secrets-controller 101 | name: sealed-secrets-controller 102 | namespace: sealed-secrets 103 | roleRef: 104 | apiGroup: rbac.authorization.k8s.io 105 | kind: Role 106 | name: sealed-secrets-key-admin 107 | subjects: 108 | - kind: ServiceAccount 109 | name: sealed-secrets-controller 110 | namespace: sealed-secrets 111 | --- 112 | apiVersion: rbac.authorization.k8s.io/v1 113 | kind: ClusterRoleBinding 114 | metadata: 115 | labels: 116 | name: sealed-secrets-controller 117 | name: sealed-secrets-controller 118 | roleRef: 119 | apiGroup: rbac.authorization.k8s.io 120 | kind: ClusterRole 121 | name: secrets-unsealer 122 | subjects: 123 | - kind: ServiceAccount 124 | name: sealed-secrets-controller 125 | namespace: sealed-secrets 126 | --- 127 | apiVersion: rbac.authorization.k8s.io/v1 128 | kind: ClusterRole 129 | metadata: 130 | labels: 131 | name: secrets-unsealer 132 | name: secrets-unsealer 133 | rules: 134 | - apiGroups: 135 | - bitnami.com 136 | resources: 137 | - sealedsecrets 138 | verbs: 139 | - get 140 | - list 141 | - watch 142 | - apiGroups: 143 | - bitnami.com 144 | resources: 145 | - sealedsecrets/status 146 | verbs: 147 | - update 148 | - apiGroups: 149 | - "" 150 | resources: 151 | - secrets 152 | verbs: 153 | - get 154 | - create 155 | - update 156 | - delete 157 | - apiGroups: 158 | - "" 159 | resources: 160 | - events 161 | verbs: 162 | - create 163 | - patch 164 | --- 165 | apiVersion: v1 166 | kind: ServiceAccount 167 | metadata: 168 | labels: 169 | name: sealed-secrets-controller 170 | name: sealed-secrets-controller 171 | namespace: sealed-secrets 172 | --- 173 | apiVersion: apps/v1 174 | kind: Deployment 175 | metadata: 176 | labels: 177 | name: sealed-secrets-controller 178 | name: sealed-secrets-controller 179 | namespace: sealed-secrets 180 | spec: 181 | minReadySeconds: 30 182 | replicas: 1 183 | revisionHistoryLimit: 10 184 | selector: 185 | matchLabels: 186 | name: sealed-secrets-controller 187 | strategy: 188 | rollingUpdate: 189 | maxSurge: 25% 190 | maxUnavailable: 25% 191 | type: RollingUpdate 192 | template: 193 | metadata: 194 | annotations: {} 195 | labels: 196 | name: sealed-secrets-controller 197 | spec: 198 | containers: 199 | - args: [] 200 | command: 201 | - controller 202 | env: [] 203 | image: quay.io/bitnami/sealed-secrets-controller:v0.16.0 204 | imagePullPolicy: Always 205 | livenessProbe: 206 | httpGet: 207 | path: /healthz 208 | port: http 209 | name: sealed-secrets-controller 210 | ports: 211 | - containerPort: 8080 212 | name: http 213 | readinessProbe: 214 | httpGet: 215 | path: /healthz 216 | port: http 217 | securityContext: 218 | readOnlyRootFilesystem: true 219 | runAsNonRoot: true 220 | runAsUser: 1001 221 | stdin: false 222 | tty: false 223 | volumeMounts: 224 | - mountPath: /tmp 225 | name: tmp 226 | imagePullSecrets: [] 227 | initContainers: [] 228 | securityContext: 229 | fsGroup: 65534 230 | serviceAccountName: sealed-secrets-controller 231 | terminationGracePeriodSeconds: 30 232 | volumes: 233 | - emptyDir: {} 234 | name: tmp 235 | -------------------------------------------------------------------------------- /crossplane.sh: -------------------------------------------------------------------------------- 1 | ##!/bin/bash 2 | 3 | # 4 | # The Crossplane CLI extends kubectl with functionality to build, push, and install Crossplane packages 5 | # 6 | curl -sL https://raw.githubusercontent.com/crossplane/crossplane/release-1.0/install.sh | sh 7 | sudo mv kubectl-crossplane /usr/local/bin 8 | 9 | # 10 | # Install Crossplane on your "management" cluster 11 | # 12 | kubectl create namespace crossplane-system 13 | helm repo add crossplane-stable https://charts.crossplane.io/stable 14 | helm repo update 15 | 16 | # 17 | # Install Crossplane core components using Helm chart 18 | # 19 | helm install crossplane --namespace crossplane-system crossplane-stable/crossplane --version 1.4.1 20 | 21 | # 22 | # Providers extend Crossplane with custom resources that can be used to declaratively configure a system. 23 | # In order to provision a resource, a CRD needs to be registered in your Kubernetes cluster and its controller should be watching the Custom Resources those CRDs define. 24 | # Crossplane provider packages contain many CRDs and their controllers. 25 | # The 'provider-aws' package is the Crossplane infrastructure provider for AWS. This package contains the followig: 26 | # 1. Custom Resource Definitions (CRDs) that model AWS infrastructure and services (e.g. RDS, S3, EKS clusters, etc.) These are called 'managed resources' 27 | # 2. Controllers to provision these resources in AWS based on the users desired state captured in CRDs they create 28 | # 3. Implementations of Crossplane's portable resource abstractions, enabling AWS resources to fulfill a user's general need for cloud services 29 | # 30 | # The core Crossplane controller can install provider controllers and CRDs for you through its own provider packaging mechanism, which is triggered by the application of a 'Provider' resource. 31 | # In order to request installation of the provider-aws package, apply the 'aws-provider.yaml' resource to the cluster where Crossplane is running. 32 | # Providers can be installed using the 'kubectl crossplane install provider' command as well. 33 | # Check out documentation on installing providers: https://crossplane.io/docs/v1.3/concepts/providers.html 34 | # 35 | cd crossplane-imperative 36 | kubectl apply -f aws-provider.yaml 37 | 38 | # 39 | # In order to authenticate with the external provider API such as AWS, the provider controllers need to have access to credentials. 40 | # It could be an IAM User for AWS 41 | # An AWS user with Administrative privileges is needed to enable Crossplane to create the required resources 42 | # We wil have to first create a configuration file, secrets.conf, with credeantials of an AWS account in the following format. 43 | # 44 | # [default] 45 | # aws_access_key_id = XXXXXXXXXXXXXX 46 | # aws_secret_access_key = XXXXXXXXXXXXXX 47 | # 48 | # Then using that file, a Kubernetes Secret is created as follows 49 | # 50 | kubectl -n crossplane-system create secret generic aws-credentials --from-file=credentials=./secrets.conf 51 | 52 | # 53 | # Create a ProviderConfig resource, referencing the above Secret 54 | # 55 | kubectl apply -f aws-providerconfig.yaml 56 | 57 | 58 | # 59 | # Crossplane goes beyond simply modelling infrastructure primitives as ‘managed resources’. 60 | # Composition is a concept that allows platform builders to define new custom resources that are composed of managed resources, like an RDS instance 61 | # Crossplane calls these “composite resources” (XRs). 62 | # Composition can be used to build a catalogue of custom resources and classes of configuration that fit the needs and opinions of your organisation. 63 | # Crossplane uses two special resources to define and configure these new composite resources: 64 | # A CompositeResourceDefinition (XRD) defines a new kind of composite resource, including its schema. An XRD may optionally offer a claim (XRC). 65 | # A Composition specifies which managed resources a composite resource will be composed of, and how they should be configured. 66 | # You can create multiple Composition options for each composite resource. 67 | # Check out the composition documentation: https://crossplane.io/docs/v1.3/concepts/composition.html 68 | # 69 | # CompositeResourceDefinitions (XRDs) and Compositions may be packaged and installed as a configuration. 70 | # A configuration is a package of composition configuration that can easily be installed to Crossplane by creating a declarative 'Configuration' resource, or by using 'kubectl crossplane install configuration'. 71 | # Check out the documentation on creating configuration: https://crossplane.io/docs/v1.3/getting-started/create-configuration.html 72 | # 73 | 74 | # 75 | # Create a package for EKS cluster creation 76 | # This package will help create a new VPC with 2 private/public subnets, IGW, NATGW and the EKS cluster with managed node group 77 | # Push this package to a repository in an image registry 78 | # 79 | cd eks-configuration 80 | kubectl crossplane build configuration 81 | kubectl crossplane push configuration public.ecr.aws/awsvijisarathy/crossplane-eks-composition:6.0.0 82 | 83 | 84 | # 85 | # Install the package to a cluster 86 | # 87 | kubectl crossplane install configuration public.ecr.aws/awsvijisarathy/crossplane-eks-composition:2.0.0 88 | 89 | # 90 | # Check if the package and the XRDs defined in it were installed properly 91 | # 92 | kubectl get Configuration crossplane-eks-composition 93 | kubectl get CompositeResourceDefinition eksclusters.eks.sarathy.io 94 | 95 | # 96 | # Create an EKS cluster and a nodegroup using an XR 97 | # 98 | kubectl apply -f eks-cluster-xr.yaml 99 | 100 | # 101 | # Here are a set of CLI commands to look at various resources 102 | # 103 | kubectl get crossplane # get all resources related to Crossplane. 104 | kubectl get managed # get all resources that represent a unit of external infrastructure such as RDSInstance. 105 | kubectl get composite # get all resources that represent an XR 106 | 107 | 108 | # 109 | # Cleanup 110 | # 111 | kubectl delete -f eks-cluster-xr.yaml 112 | kubectl delete -f aws-providerconfig.yaml 113 | kubectl delete -f aws-provider.yaml 114 | helm uninstall crossplane --namespace crossplane-system 115 | 116 | -------------------------------------------------------------------------------- /Grafana-Metrics-Dashboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": "-- Grafana --", 7 | "enable": true, 8 | "hide": true, 9 | "iconColor": "rgba(0, 211, 255, 1)", 10 | "name": "Annotations & Alerts", 11 | "target": { 12 | "limit": 100, 13 | "matchAny": false, 14 | "tags": [], 15 | "type": "dashboard" 16 | }, 17 | "type": "dashboard" 18 | } 19 | ] 20 | }, 21 | "editable": true, 22 | "fiscalYearStartMonth": 0, 23 | "gnetId": null, 24 | "graphTooltip": 0, 25 | "id": 34, 26 | "links": [], 27 | "liveNow": false, 28 | "panels": [ 29 | { 30 | "aliasColors": {}, 31 | "bars": false, 32 | "dashLength": 10, 33 | "dashes": false, 34 | "datasource": "Prometheus-West", 35 | "fill": 1, 36 | "fillGradient": 0, 37 | "gridPos": { 38 | "h": 9, 39 | "w": 12, 40 | "x": 0, 41 | "y": 0 42 | }, 43 | "hiddenSeries": false, 44 | "id": 2, 45 | "legend": { 46 | "alignAsTable": true, 47 | "avg": false, 48 | "current": false, 49 | "max": false, 50 | "min": false, 51 | "show": true, 52 | "total": false, 53 | "values": false 54 | }, 55 | "lines": true, 56 | "linewidth": 1, 57 | "nullPointMode": "null", 58 | "options": { 59 | "alertThreshold": true 60 | }, 61 | "percentage": false, 62 | "pluginVersion": "8.2.5", 63 | "pointradius": 2, 64 | "points": false, 65 | "renderer": "flot", 66 | "seriesOverrides": [], 67 | "spaceLength": 10, 68 | "stack": false, 69 | "steppedLine": false, 70 | "targets": [ 71 | { 72 | "exemplar": true, 73 | "expr": "sum(rate(http_requests_total[5m]))", 74 | "interval": "", 75 | "legendFormat": "Requests per Second", 76 | "refId": "A" 77 | } 78 | ], 79 | "thresholds": [], 80 | "timeFrom": null, 81 | "timeRegions": [], 82 | "timeShift": null, 83 | "title": "HTTP Request Rate", 84 | "tooltip": { 85 | "shared": true, 86 | "sort": 0, 87 | "value_type": "individual" 88 | }, 89 | "type": "graph", 90 | "xaxis": { 91 | "buckets": null, 92 | "mode": "time", 93 | "name": null, 94 | "show": true, 95 | "values": [] 96 | }, 97 | "yaxes": [ 98 | { 99 | "$$hashKey": "object:753", 100 | "format": "short", 101 | "label": null, 102 | "logBase": 1, 103 | "max": null, 104 | "min": null, 105 | "show": true 106 | }, 107 | { 108 | "$$hashKey": "object:754", 109 | "format": "short", 110 | "label": null, 111 | "logBase": 1, 112 | "max": null, 113 | "min": null, 114 | "show": true 115 | } 116 | ], 117 | "yaxis": { 118 | "align": false, 119 | "alignLevel": null 120 | } 121 | }, 122 | { 123 | "aliasColors": {}, 124 | "bars": false, 125 | "dashLength": 10, 126 | "dashes": false, 127 | "datasource": "Prometheus-West", 128 | "fill": 1, 129 | "fillGradient": 0, 130 | "gridPos": { 131 | "h": 8, 132 | "w": 12, 133 | "x": 0, 134 | "y": 9 135 | }, 136 | "hiddenSeries": false, 137 | "id": 6, 138 | "legend": { 139 | "avg": false, 140 | "current": false, 141 | "max": false, 142 | "min": false, 143 | "show": true, 144 | "total": false, 145 | "values": false 146 | }, 147 | "lines": true, 148 | "linewidth": 1, 149 | "nullPointMode": "null", 150 | "options": { 151 | "alertThreshold": true 152 | }, 153 | "percentage": false, 154 | "pluginVersion": "8.2.5", 155 | "pointradius": 2, 156 | "points": false, 157 | "renderer": "flot", 158 | "seriesOverrides": [], 159 | "spaceLength": 10, 160 | "stack": false, 161 | "steppedLine": false, 162 | "targets": [ 163 | { 164 | "exemplar": true, 165 | "expr": "sum(rate(request_duration_milliseconds_sum[5m]))/sum(rate(request_duration_milliseconds_count[5m]))", 166 | "hide": false, 167 | "interval": "", 168 | "legendFormat": "Average Response Latency", 169 | "refId": "B" 170 | } 171 | ], 172 | "thresholds": [], 173 | "timeFrom": null, 174 | "timeRegions": [], 175 | "timeShift": null, 176 | "title": "Response Latency", 177 | "tooltip": { 178 | "shared": true, 179 | "sort": 0, 180 | "value_type": "individual" 181 | }, 182 | "type": "graph", 183 | "xaxis": { 184 | "buckets": null, 185 | "mode": "time", 186 | "name": null, 187 | "show": true, 188 | "values": [] 189 | }, 190 | "yaxes": [ 191 | { 192 | "$$hashKey": "object:335", 193 | "format": "short", 194 | "label": null, 195 | "logBase": 1, 196 | "max": null, 197 | "min": null, 198 | "show": true 199 | }, 200 | { 201 | "$$hashKey": "object:336", 202 | "format": "short", 203 | "label": null, 204 | "logBase": 1, 205 | "max": null, 206 | "min": null, 207 | "show": true 208 | } 209 | ], 210 | "yaxis": { 211 | "align": false, 212 | "alignLevel": null 213 | } 214 | } 215 | ], 216 | "refresh": false, 217 | "schemaVersion": 32, 218 | "style": "dark", 219 | "tags": [], 220 | "templating": { 221 | "list": [] 222 | }, 223 | "time": { 224 | "from": "now-15m", 225 | "to": "now" 226 | }, 227 | "timepicker": {}, 228 | "timezone": "", 229 | "title": "Grafana Metrics Dashboard", 230 | "uid": "5wqWkSR7k", 231 | "version": 4 232 | } -------------------------------------------------------------------------------- /crossplane-imperative/eks-configuration/composition.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.crossplane.io/v1 3 | kind: Composition 4 | metadata: 5 | name: amazon-eks-cluster 6 | labels: 7 | provider: aws 8 | service: eks 9 | compute: managed 10 | spec: 11 | writeConnectionSecretsToNamespace: crossplane-system 12 | compositeTypeRef: 13 | apiVersion: eks.sarathy.io/v1beta1 14 | kind: EKSCluster 15 | 16 | patchSets: 17 | - name: common-parameters 18 | patches: 19 | - fromFieldPath: "spec.parameters.region" 20 | toFieldPath: "spec.forProvider.region" 21 | 22 | resources: 23 | - name: vpc 24 | base: 25 | apiVersion: ec2.aws.crossplane.io/v1beta1 26 | kind: VPC 27 | spec: 28 | forProvider: 29 | enableDnsSupport: true 30 | enableDnsHostNames: true 31 | tags: 32 | - key: Name 33 | patches: 34 | - type: PatchSet 35 | patchSetName: common-parameters 36 | - fromFieldPath: spec.parameters.vpc-cidrBlock 37 | toFieldPath: spec.forProvider.cidrBlock 38 | - fromFieldPath: spec.parameters.vpc-name 39 | toFieldPath: spec.forProvider.tags[0].value 40 | 41 | - name: internetgateway 42 | base: 43 | apiVersion: ec2.aws.crossplane.io/v1beta1 44 | kind: InternetGateway 45 | metadata: 46 | labels: 47 | type: igw 48 | spec: 49 | forProvider: 50 | vpcIdSelector: 51 | matchControllerRef: true 52 | tags: 53 | - key: Name 54 | patches: 55 | - type: PatchSet 56 | patchSetName: common-parameters 57 | - type: CombineFromComposite 58 | combine: 59 | variables: 60 | - fromFieldPath: spec.parameters.vpc-name 61 | strategy: string 62 | string: 63 | fmt: "%s-igw" 64 | toFieldPath: spec.forProvider.tags[0].value 65 | policy: 66 | fromFieldPath: Required 67 | 68 | - name: subnet-public-1 69 | base: 70 | apiVersion: ec2.aws.crossplane.io/v1beta1 71 | kind: Subnet 72 | metadata: 73 | labels: 74 | type: subnet 75 | visibility: public 76 | spec: 77 | forProvider: 78 | mapPublicIpOnLaunch: true 79 | vpcIdSelector: 80 | matchControllerRef: true 81 | tags: 82 | - key: Name 83 | - key: kubernetes.io/role/elb 84 | value: "1" 85 | patches: 86 | - type: CombineFromComposite 87 | combine: 88 | variables: 89 | - fromFieldPath: spec.parameters.vpc-name 90 | - fromFieldPath: spec.parameters.subnet1-public-name 91 | strategy: string 92 | string: 93 | fmt: "%s-%s" 94 | toFieldPath: spec.forProvider.tags[0].value 95 | policy: 96 | fromFieldPath: Required 97 | - type: PatchSet 98 | patchSetName: common-parameters 99 | - fromFieldPath: spec.parameters.subnet1-public-cidrBlock 100 | toFieldPath: spec.forProvider.cidrBlock 101 | - fromFieldPath: spec.parameters.subnet1-public-availabilityZone 102 | toFieldPath: spec.forProvider.availabilityZone 103 | - fromFieldPath: spec.parameters.subnet1-public-availabilityZone 104 | toFieldPath: metadata.labels.zone 105 | 106 | - name: subnet-public-2 107 | base: 108 | apiVersion: ec2.aws.crossplane.io/v1beta1 109 | kind: Subnet 110 | metadata: 111 | labels: 112 | type: subnet 113 | visibility: public 114 | spec: 115 | forProvider: 116 | mapPublicIpOnLaunch: true 117 | vpcIdSelector: 118 | matchControllerRef: true 119 | tags: 120 | - key: Name 121 | - key: kubernetes.io/role/elb 122 | value: "1" 123 | patches: 124 | - type: CombineFromComposite 125 | combine: 126 | variables: 127 | - fromFieldPath: spec.parameters.vpc-name 128 | - fromFieldPath: spec.parameters.subnet2-public-name 129 | strategy: string 130 | string: 131 | fmt: "%s-%s" 132 | toFieldPath: spec.forProvider.tags[0].value 133 | policy: 134 | fromFieldPath: Required 135 | - type: PatchSet 136 | patchSetName: common-parameters 137 | - fromFieldPath: spec.parameters.subnet2-public-cidrBlock 138 | toFieldPath: spec.forProvider.cidrBlock 139 | - fromFieldPath: spec.parameters.subnet2-public-availabilityZone 140 | toFieldPath: spec.forProvider.availabilityZone 141 | - fromFieldPath: spec.parameters.subnet2-public-availabilityZone 142 | toFieldPath: metadata.labels.zone 143 | 144 | - name: subnet-private-1 145 | base: 146 | apiVersion: ec2.aws.crossplane.io/v1beta1 147 | kind: Subnet 148 | metadata: 149 | labels: 150 | type: subnet 151 | visibility: private 152 | spec: 153 | forProvider: 154 | mapPublicIpOnLaunch: false 155 | vpcIdSelector: 156 | matchControllerRef: true 157 | tags: 158 | - key: Name 159 | - key: kubernetes.io/role/internal-elb 160 | value: "1" 161 | patches: 162 | - type: CombineFromComposite 163 | combine: 164 | variables: 165 | - fromFieldPath: spec.parameters.vpc-name 166 | - fromFieldPath: spec.parameters.subnet1-private-name 167 | strategy: string 168 | string: 169 | fmt: "%s-%s" 170 | toFieldPath: spec.forProvider.tags[0].value 171 | policy: 172 | fromFieldPath: Required 173 | - type: PatchSet 174 | patchSetName: common-parameters 175 | - fromFieldPath: spec.parameters.subnet1-private-cidrBlock 176 | toFieldPath: spec.forProvider.cidrBlock 177 | - fromFieldPath: spec.parameters.subnet1-private-availabilityZone 178 | toFieldPath: spec.forProvider.availabilityZone 179 | - fromFieldPath: spec.parameters.subnet1-private-availabilityZone 180 | toFieldPath: metadata.labels.zone 181 | 182 | - name: subnet-private-2 183 | base: 184 | apiVersion: ec2.aws.crossplane.io/v1beta1 185 | kind: Subnet 186 | metadata: 187 | labels: 188 | type: subnet 189 | visibility: private 190 | spec: 191 | forProvider: 192 | mapPublicIpOnLaunch: false 193 | vpcIdSelector: 194 | matchControllerRef: true 195 | tags: 196 | - key: Name 197 | - key: kubernetes.io/role/internal-elb 198 | value: "1" 199 | patches: 200 | - type: CombineFromComposite 201 | combine: 202 | variables: 203 | - fromFieldPath: spec.parameters.vpc-name 204 | - fromFieldPath: spec.parameters.subnet2-private-name 205 | strategy: string 206 | string: 207 | fmt: "%s-%s" 208 | toFieldPath: spec.forProvider.tags[0].value 209 | policy: 210 | fromFieldPath: Required 211 | - type: PatchSet 212 | patchSetName: common-parameters 213 | - fromFieldPath: spec.parameters.subnet2-private-cidrBlock 214 | toFieldPath: spec.forProvider.cidrBlock 215 | - fromFieldPath: spec.parameters.subnet2-private-availabilityZone 216 | toFieldPath: spec.forProvider.availabilityZone 217 | - fromFieldPath: spec.parameters.subnet2-private-availabilityZone 218 | toFieldPath: metadata.labels.zone 219 | 220 | - name: elastic-ip-1 221 | base: 222 | apiVersion: ec2.aws.crossplane.io/v1beta1 223 | kind: Address 224 | metadata: 225 | labels: 226 | type: eip-1 227 | spec: 228 | forProvider: 229 | domain: vpc 230 | patches: 231 | - type: PatchSet 232 | patchSetName: common-parameters 233 | 234 | - name: elastic-ip-2 235 | base: 236 | apiVersion: ec2.aws.crossplane.io/v1beta1 237 | kind: Address 238 | metadata: 239 | labels: 240 | type: eip-2 241 | spec: 242 | forProvider: 243 | domain: vpc 244 | patches: 245 | - type: PatchSet 246 | patchSetName: common-parameters 247 | 248 | - name: natgateway-1 249 | base: 250 | apiVersion: ec2.aws.crossplane.io/v1beta1 251 | kind: NATGateway 252 | metadata: 253 | labels: 254 | type: natgw-1 255 | spec: 256 | forProvider: 257 | allocationIdSelector: 258 | matchLabels: 259 | type: eip-1 260 | vpcIdSelector: 261 | matchControllerRef: true 262 | subnetIdSelector: 263 | matchLabels: 264 | type: subnet 265 | visibility: public 266 | tags: 267 | - key: Name 268 | patches: 269 | - type: CombineFromComposite 270 | combine: 271 | variables: 272 | - fromFieldPath: spec.parameters.vpc-name 273 | strategy: string 274 | string: 275 | fmt: "%s-nat-gateway-1" 276 | toFieldPath: spec.forProvider.tags[0].value 277 | policy: 278 | fromFieldPath: Required 279 | - type: PatchSet 280 | patchSetName: common-parameters 281 | - fromFieldPath: spec.parameters.subnet1-public-availabilityZone 282 | toFieldPath: spec.forProvider.subnetIdSelector.matchLabels.zone 283 | 284 | - name: natgateway-2 285 | base: 286 | apiVersion: ec2.aws.crossplane.io/v1beta1 287 | kind: NATGateway 288 | metadata: 289 | labels: 290 | type: natgw-2 291 | spec: 292 | forProvider: 293 | allocationIdSelector: 294 | matchLabels: 295 | type: eip-2 296 | vpcIdSelector: 297 | matchControllerRef: true 298 | subnetIdSelector: 299 | matchLabels: 300 | type: subnet 301 | visibility: public 302 | tags: 303 | - key: Name 304 | patches: 305 | - type: CombineFromComposite 306 | combine: 307 | variables: 308 | - fromFieldPath: spec.parameters.vpc-name 309 | strategy: string 310 | string: 311 | fmt: "%s-nat-gateway-2" 312 | toFieldPath: spec.forProvider.tags[0].value 313 | policy: 314 | fromFieldPath: Required 315 | - type: PatchSet 316 | patchSetName: common-parameters 317 | - fromFieldPath: spec.parameters.subnet2-public-availabilityZone 318 | toFieldPath: spec.forProvider.subnetIdSelector.matchLabels.zone 319 | 320 | - name: routetable-public 321 | base: 322 | apiVersion: ec2.aws.crossplane.io/v1beta1 323 | kind: RouteTable 324 | spec: 325 | forProvider: 326 | vpcIdSelector: 327 | matchControllerRef: true 328 | routes: 329 | - destinationCidrBlock: 0.0.0.0/0 330 | gatewayIdSelector: 331 | matchLabels: 332 | type: igw 333 | associations: 334 | - subnetIdSelector: 335 | matchLabels: 336 | type: subnet 337 | visibility: public 338 | - subnetIdSelector: 339 | matchLabels: 340 | type: subnet 341 | visibility: public 342 | tags: 343 | - key: Name 344 | patches: 345 | - type: CombineFromComposite 346 | combine: 347 | variables: 348 | - fromFieldPath: spec.parameters.vpc-name 349 | strategy: string 350 | string: 351 | fmt: "%s-public-route-table" 352 | toFieldPath: spec.forProvider.tags[0].value 353 | policy: 354 | fromFieldPath: Required 355 | - type: PatchSet 356 | patchSetName: common-parameters 357 | - fromFieldPath: spec.parameters.subnet1-public-availabilityZone 358 | toFieldPath: spec.forProvider.associations[0].subnetIdSelector.matchLabels.zone 359 | - fromFieldPath: spec.parameters.subnet2-public-availabilityZone 360 | toFieldPath: spec.forProvider.associations[1].subnetIdSelector.matchLabels.zone 361 | 362 | - name: routetable-private-1 363 | base: 364 | apiVersion: ec2.aws.crossplane.io/v1beta1 365 | kind: RouteTable 366 | spec: 367 | forProvider: 368 | vpcIdSelector: 369 | matchControllerRef: true 370 | routes: 371 | - destinationCidrBlock: 0.0.0.0/0 372 | natGatewayIdSelector: 373 | matchLabels: 374 | type: natgw-1 375 | associations: 376 | - subnetIdSelector: 377 | matchLabels: 378 | type: subnet 379 | visibility: private 380 | tags: 381 | - key: Name 382 | patches: 383 | - type: CombineFromComposite 384 | combine: 385 | variables: 386 | - fromFieldPath: spec.parameters.vpc-name 387 | strategy: string 388 | string: 389 | fmt: "%s-private-route-table-1" 390 | toFieldPath: spec.forProvider.tags[0].value 391 | policy: 392 | fromFieldPath: Required 393 | - type: PatchSet 394 | patchSetName: common-parameters 395 | - fromFieldPath: spec.parameters.subnet1-public-availabilityZone 396 | toFieldPath: spec.forProvider.associations[0].subnetIdSelector.matchLabels.zone 397 | 398 | - name: routetable-private-2 399 | base: 400 | apiVersion: ec2.aws.crossplane.io/v1beta1 401 | kind: RouteTable 402 | spec: 403 | forProvider: 404 | vpcIdSelector: 405 | matchControllerRef: true 406 | routes: 407 | - destinationCidrBlock: 0.0.0.0/0 408 | natGatewayIdSelector: 409 | matchLabels: 410 | type: natgw-2 411 | associations: 412 | - subnetIdSelector: 413 | matchLabels: 414 | type: subnet 415 | visibility: private 416 | tags: 417 | - key: Name 418 | patches: 419 | - type: CombineFromComposite 420 | combine: 421 | variables: 422 | - fromFieldPath: spec.parameters.vpc-name 423 | strategy: string 424 | string: 425 | fmt: "%s-private-route-table-2" 426 | toFieldPath: spec.forProvider.tags[0].value 427 | policy: 428 | fromFieldPath: Required 429 | - type: PatchSet 430 | patchSetName: common-parameters 431 | - fromFieldPath: spec.parameters.subnet2-public-availabilityZone 432 | toFieldPath: spec.forProvider.associations[0].subnetIdSelector.matchLabels.zone 433 | 434 | - name: eks-cluster 435 | base: 436 | apiVersion: eks.aws.crossplane.io/v1beta1 437 | kind: Cluster 438 | spec: 439 | forProvider: 440 | resourcesVpcConfig: 441 | endpointPrivateAccess: false 442 | endpointPublicAccess: true 443 | subnetIdSelector: 444 | matchLabels: 445 | type: subnet 446 | writeConnectionSecretToRef: 447 | namespace: crossplane-system 448 | patches: 449 | - type: PatchSet 450 | patchSetName: common-parameters 451 | - fromFieldPath: "spec.parameters.k8s-version" 452 | toFieldPath: "spec.forProvider.version" 453 | - fromFieldPath: "metadata.uid" 454 | toFieldPath: "spec.writeConnectionSecretToRef.name" 455 | transforms: 456 | - type: string 457 | string: 458 | fmt: "%s-ekscluster-connection" 459 | - fromFieldPath: "spec.parameters.cluster-role" 460 | toFieldPath: "spec.forProvider.roleArn" 461 | connectionDetails: 462 | - name: cluster-ca 463 | fromConnectionSecretKey: clusterCA 464 | - name: apiserver-endpoint 465 | fromConnectionSecretKey: endpoint 466 | - name: value 467 | fromConnectionSecretKey: kubeconfig 468 | 469 | - name: eks-nodegroup 470 | base: 471 | apiVersion: eks.aws.crossplane.io/v1alpha1 472 | kind: NodeGroup 473 | spec: 474 | forProvider: 475 | instanceTypes: 476 | - m5.large 477 | scalingConfig: 478 | minSize: 1 479 | subnetSelector: 480 | matchLabels: 481 | type: subnet 482 | visibility: private 483 | clusterNameSelector: 484 | matchControllerRef: true 485 | patches: 486 | - type: PatchSet 487 | patchSetName: common-parameters 488 | - fromFieldPath: "spec.parameters.workers-size" 489 | toFieldPath: "spec.forProvider.scalingConfig.desiredSize" 490 | - fromFieldPath: "spec.parameters.workers-size" 491 | toFieldPath: "spec.forProvider.scalingConfig.maxSize" 492 | - fromFieldPath: "spec.parameters.workload-type" 493 | toFieldPath: "spec.forProvider.amiType" 494 | transforms: 495 | - type: map 496 | map: 497 | gpu: AL2_x86_64_GPU 498 | non-gpu: AL2_x86_64 499 | - fromFieldPath: "spec.parameters.workernode-role" 500 | toFieldPath: "spec.forProvider.nodeRole" --------------------------------------------------------------------------------