From 09566f7cb75e6f1c171b54cde0c51d7c25a56809 Mon Sep 17 00:00:00 2001 From: Fabrice Brito Date: Fri, 28 Mar 2025 11:32:50 +0100 Subject: [PATCH 1/7] adds using secrets in a python function and cli --function-credentials --- content/master/cli/command-reference.md | 6 ++ .../write-a-composition-function-in-python.md | 69 +++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/content/master/cli/command-reference.md b/content/master/cli/command-reference.md index 95303420..be56a3ee 100644 --- a/content/master/cli/command-reference.md +++ b/content/master/cli/command-reference.md @@ -108,6 +108,7 @@ spec: | `-c` | `--include-context` | Include the context in the rendered output as a resource of kind: Context. | | `-x` | `--include-full-xr` | Include a copy of the input Composite Resource spec and metadata fields in the rendered output. | | | `--timeout=` | Amount of time to wait for a function to finish. (Default 1 minute) | +| | `--function-credentials=PATH` | A YAML file or directory of YAML files specifying credentials to use for Functions to render the XR. | {{< /table >}} @@ -127,6 +128,11 @@ If a function produces Kubernetes events with statuses use the `--include-function-results` to print them along with the managed resource outputs. +### Use a secret in a function + +If a function needs a secret, use the `--function-credentials=PATH` +where `PATH` is the path to a Kubernetes secret manifest. + ### Include the composite resource Composition functions can only change the `status` field of a composite diff --git a/content/master/guides/write-a-composition-function-in-python.md b/content/master/guides/write-a-composition-function-in-python.md index 58aad756..d54276cc 100644 --- a/content/master/guides/write-a-composition-function-in-python.md +++ b/content/master/guides/write-a-composition-function-in-python.md @@ -733,3 +733,72 @@ up continuous integration (CI) using lint, test, and build your function. You can see how the template configures CI by reading `.github/workflows/ci.yaml`. {{}} + +## Using credentials in the function + +To access a secret, the `composition.yaml` step declares it with: + +```yaml +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: create-buckets +spec: + compositeTypeRef: + apiVersion: example.crossplane.io/v1 + kind: XBuckets + mode: Pipeline + pipeline: + - step: create-buckets + credentials: + - name: function-credentials + secretRef: + name: secret-name + namespace: crossplane-system + source: Secret + functionRef: + name: function-xbuckets +``` + +Where `secret-name` is the kubernetes secret name. + +Edit the `RunFunction` method to read the credentials using `req.credentials`: + +{{}} +See [apiextensions.fn.proto.v1.RunFunctionRequest](https://buf.build/crossplane/crossplane/docs/main:apiextensions.fn.proto.v1#apiextensions.fn.proto.v1.RunFunctionRequest) +and [protobuf generated Python code ](https://protobuf.dev/reference/python/python-generated/) +to understand what kind of Python code is generated from the protobuf +and how to access the request content +{{}} + +```python +async def RunFunction(self, req: fnv1.RunFunctionRequest, _: grpc.aio.ServicerContext) -> fnv1.RunFunctionResponse: + log = self.log.bind(tag=req.meta.tag) + log.info("Running function") + + rsp = response.to(req) + + credentials = req.credentials + + username = credentials["secret-name"].credential_data.data["username"].decode("utf-8") + password = credentials["secret-name"].credential_data.data["password"].decode("utf-8") +``` + +To test the function with `crossplane render`, use: + +`crossplane render --function-credentials=secret.yaml xr.yaml composition.yaml functions.yaml` + +Where `secret.yaml` is a Kubernetes secret manifest: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: secret-name + namespace: crossplane-system +data: + username: bb..bb + password: aa..aa +type: Opaque +``` + From 48ddb4b9f770d6f101638eb1bec2ff8d1f84511b Mon Sep 17 00:00:00 2001 From: Fabrice Brito Date: Fri, 28 Mar 2025 11:32:50 +0100 Subject: [PATCH 2/7] adds using secrets in a python function and cli --function-credentials --- content/master/cli/command-reference.md | 6 ++ .../write-a-composition-function-in-python.md | 69 +++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/content/master/cli/command-reference.md b/content/master/cli/command-reference.md index 95303420..be56a3ee 100644 --- a/content/master/cli/command-reference.md +++ b/content/master/cli/command-reference.md @@ -108,6 +108,7 @@ spec: | `-c` | `--include-context` | Include the context in the rendered output as a resource of kind: Context. | | `-x` | `--include-full-xr` | Include a copy of the input Composite Resource spec and metadata fields in the rendered output. | | | `--timeout=` | Amount of time to wait for a function to finish. (Default 1 minute) | +| | `--function-credentials=PATH` | A YAML file or directory of YAML files specifying credentials to use for Functions to render the XR. | {{< /table >}} @@ -127,6 +128,11 @@ If a function produces Kubernetes events with statuses use the `--include-function-results` to print them along with the managed resource outputs. +### Use a secret in a function + +If a function needs a secret, use the `--function-credentials=PATH` +where `PATH` is the path to a Kubernetes secret manifest. + ### Include the composite resource Composition functions can only change the `status` field of a composite diff --git a/content/master/guides/write-a-composition-function-in-python.md b/content/master/guides/write-a-composition-function-in-python.md index 58aad756..d54276cc 100644 --- a/content/master/guides/write-a-composition-function-in-python.md +++ b/content/master/guides/write-a-composition-function-in-python.md @@ -733,3 +733,72 @@ up continuous integration (CI) using lint, test, and build your function. You can see how the template configures CI by reading `.github/workflows/ci.yaml`. {{}} + +## Using credentials in the function + +To access a secret, the `composition.yaml` step declares it with: + +```yaml +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: create-buckets +spec: + compositeTypeRef: + apiVersion: example.crossplane.io/v1 + kind: XBuckets + mode: Pipeline + pipeline: + - step: create-buckets + credentials: + - name: function-credentials + secretRef: + name: secret-name + namespace: crossplane-system + source: Secret + functionRef: + name: function-xbuckets +``` + +Where `secret-name` is the kubernetes secret name. + +Edit the `RunFunction` method to read the credentials using `req.credentials`: + +{{}} +See [apiextensions.fn.proto.v1.RunFunctionRequest](https://buf.build/crossplane/crossplane/docs/main:apiextensions.fn.proto.v1#apiextensions.fn.proto.v1.RunFunctionRequest) +and [protobuf generated Python code ](https://protobuf.dev/reference/python/python-generated/) +to understand what kind of Python code is generated from the protobuf +and how to access the request content +{{}} + +```python +async def RunFunction(self, req: fnv1.RunFunctionRequest, _: grpc.aio.ServicerContext) -> fnv1.RunFunctionResponse: + log = self.log.bind(tag=req.meta.tag) + log.info("Running function") + + rsp = response.to(req) + + credentials = req.credentials + + username = credentials["secret-name"].credential_data.data["username"].decode("utf-8") + password = credentials["secret-name"].credential_data.data["password"].decode("utf-8") +``` + +To test the function with `crossplane render`, use: + +`crossplane render --function-credentials=secret.yaml xr.yaml composition.yaml functions.yaml` + +Where `secret.yaml` is a Kubernetes secret manifest: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: secret-name + namespace: crossplane-system +data: + username: bb..bb + password: aa..aa +type: Opaque +``` + From 822c4e33e47ea21324bbb30a2014d7f14f03173d Mon Sep 17 00:00:00 2001 From: Jared Watts Date: Thu, 27 Mar 2025 16:37:26 -0700 Subject: [PATCH 3/7] full walkthrough for get started with managed resources guide Signed-off-by: Jared Watts --- .../get-started-with-managed-resources.md | 157 +++++++++++------- 1 file changed, 95 insertions(+), 62 deletions(-) diff --git a/content/v2.0-preview/get-started/get-started-with-managed-resources.md b/content/v2.0-preview/get-started/get-started-with-managed-resources.md index d5febeb0..d7a0c727 100644 --- a/content/v2.0-preview/get-started/get-started-with-managed-resources.md +++ b/content/v2.0-preview/get-started/get-started-with-managed-resources.md @@ -3,9 +3,8 @@ title: Get Started With Managed Resources weight: 200 --- -Connect Crossplane to AWS to create and manage cloud resources from Kubernetes -with -[provider-upjet-aws](https://github.com/crossplane-contrib/provider-upjet-aws). +Connect Crossplane to AWS to create and manage cloud resources from Kubernetes +with [provider-upjet-aws](https://github.com/crossplane-contrib/provider-upjet-aws). ## Prerequisites @@ -16,10 +15,37 @@ This quickstart requires: * An AWS account with permissions to create an S3 storage bucket * AWS [access keys](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds) +## About Managed Resources in Crossplane v2 +A _managed resource_ is anything Crossplane creates and manages outside of the +Kubernetes cluster. + +This guide creates an AWS S3 bucket with Crossplane. + +The S3 bucket is a _managed resource_. + +Crossplane v2 allows you to compose namespaced resources. To better support this +new ability, managed resources (MRs) are now namespaced in Providers that have +been updated for Crossplane v2. + +To support backwards compatibility while users are adopting Crossplane v2, each +provider will offer the legacy cluster scoped MRs in addition to the new +namespaced MRs. + +For example, when the AWS provider that has been upated to support Crossplane v2 +is installed during this guide, you will see two CRDs for each type of managed +resource: + +1. A legacy cluster scoped MR in the `*.aws.upbound.io` API group +1. A namespaced MR in the `*.aws.m.upbound.io` API group + +{{< hint type="tip" >}} +More about namespaced managed resources can be read in the [Crossplane v2 proposal](https://github.com/crossplane/crossplane/pull/6255). +{{< /hint >}} + ## Install the AWS provider -Install the AWS S3 provider into the Kubernetes cluster with a Kubernetes -configuration file. +Install the AWS S3 provider into the Kubernetes cluster with a Kubernetes +configuration file. ```yaml {label="provider",copy-lines="all"} cat <}}Provider{{}} installs the Kubernetes _Custom Resource Definitions_ (CRDs) representing AWS S3 -services. These CRDs allow you to create AWS resources directly inside +services. These CRDs allow you to create AWS resources directly inside Kubernetes. -Verify the provider installed with `kubectl get providers`. +Verify the provider installed with `kubectl get providers`. ```shell {copy-lines="1",label="getProvider"} kubectl get providers -NAME INSTALLED HEALTHY PACKAGE AGE -crossplane-contrib-provider-family-aws True True xpkg.crossplane.io/crossplane-contrib/provider-family-aws:v1.21.1 30s -provider-aws-s3 True True xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v1.21.1 34s +NAME INSTALLED HEALTHY PACKAGE AGE +crossplane-contrib-provider-family-aws True True xpkg.crossplane.io/crossplane-contrib/provider-family-aws:v1.22.0-crossplane-v2-preview.0 27s +provider-aws-s3 True True xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v1.22.0-crossplane-v2-preview.0 31s ``` The S3 Provider installs a second Provider, the -{{}}crossplane-contrib-provider-family-aws{{}}. +{{}}crossplane-contrib-provider-family-aws{{}}. The family provider manages authentication to AWS across all AWS family -Providers. +Providers. - -You can view the new CRDs with `kubectl get crds`. +You can view the new CRDs with `kubectl get crds`. Every CRD maps to a unique AWS service Crossplane can provision and manage. {{< hint type="tip" >}} -See details about all the supported CRDs in the +See details about all the supported CRDs in the [provider examples](https://github.com/crossplane-contrib/provider-upjet-aws/tree/main/examples). {{< /hint >}} ## Create a Kubernetes secret for AWS -The provider requires credentials to create and manage AWS resources. +The provider requires credentials to create and manage AWS resources. Providers use a Kubernetes _Secret_ to connect the credentials to the provider. -Generate a Kubernetes _Secret_ from your AWS key-pair and +Generate a Kubernetes _Secret_ from your AWS key-pair and then configure the Provider to use it. ### Generate an AWS key-pair file -For basic user authentication, use an AWS Access keys key-pair file. +For basic user authentication, use an AWS Access keys key-pair file. {{< hint type="tip" >}} -The [AWS documentation](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds) +The [AWS documentation](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds) provides information on how to generate AWS Access keys. {{< /hint >}} -Create a text file containing the AWS account `aws_access_key_id` and `aws_secret_access_key`. +Create a text file containing the AWS account `aws_access_key_id` and `aws_secret_access_key`. {{< editCode >}} ```ini {copy-lines="all"} @@ -93,12 +118,12 @@ The [Authentication](https://docs.upbound.io/providers/provider-aws/authenticati {{< /hint >}} ### Create a Kubernetes secret with the AWS credentials -A Kubernetes generic secret has a name and contents. -Use -{{< hover label="kube-create-secret" line="1">}}kubectl create secret{{}} -to generate the secret object named -{{< hover label="kube-create-secret" line="2">}}aws-secret{{< /hover >}} -in the {{< hover label="kube-create-secret" line="3">}}crossplane-system{{}} namespace. +A Kubernetes generic secret has a name and contents. +Use +{{< hover label="kube-create-secret" line="1">}}kubectl create secret{{}} +to generate the secret object named +{{< hover label="kube-create-secret" line="2">}}aws-secret{{< /hover >}} +in the {{< hover label="kube-create-secret" line="3">}}crossplane-system{{}} namespace. Use the {{< hover label="kube-create-secret" line="4">}}--from-file={{}} argument to set the value to the contents of the {{< hover label="kube-create-secret" line="4">}}aws-credentials.txt{{< /hover >}} file. @@ -131,10 +156,10 @@ creds: 114 bytes ## Create a ProviderConfig A {{< hover label="providerconfig" line="3">}}ProviderConfig{{}} -customizes the settings of the AWS Provider. +customizes the settings of the AWS Provider. -Apply the -{{< hover label="providerconfig" line="3">}}ProviderConfig{{}} +Apply the +{{< hover label="providerconfig" line="3">}}ProviderConfig{{}} with the this Kubernetes configuration file: ```yaml {label="providerconfig",copy-lines="all"} cat <}}secretRef{{}}. -The -{{< hover label="providerconfig" line="11">}}spec.credentials.secretRef.name{{< /hover >}} -value is the name of the Kubernetes secret containing the AWS credentials in the +The +{{< hover label="providerconfig" line="11">}}spec.credentials.secretRef.name{{< /hover >}} +value is the name of the Kubernetes secret containing the AWS credentials in the {{< hover label="providerconfig" line="10">}}spec.credentials.secretRef.namespace{{< /hover >}}. +## Create a namespace +Before we can create our namespaced S3 bucket managed resource, we must create a +namespace for it. -## Create a managed resource -A _managed resource_ is anything Crossplane creates and manages outside of the -Kubernetes cluster. - -This guide creates an AWS S3 bucket with Crossplane. - -The S3 bucket is a _managed resource_. +```shell {label="kube-create-namespace",copy-lines="all"} +kubectl create namespace crossplane-aws-app +``` +## Create a managed resource {{< hint type="note" >}} -AWS S3 bucket names must be globally unique. To generate a unique name the example uses a random hash. +AWS S3 bucket names must be globally unique. To generate a unique name the example uses a random hash. Any unique name is acceptable. {{< /hint >}} ```yaml {label="xr"} cat <}}apiVersion{{< /hover >}} and +The {{< hover label="xr" line="2">}}apiVersion{{< /hover >}} and {{< hover label="xr" line="3">}}kind{{}} are from the provider's CRDs. +The {{< hover label="xr" line="6">}}metadata.generateName{{< /hover >}} gives a +pattern that the provider will use to create a unique name for the bucket in S3. +The generated name will look like `crossplane-bucket-`. -The {{< hover label="xr" line="5">}}metadata.generateName{{< /hover >}} value is the -name of the created S3 bucket in AWS. -This example uses the generated name `crossplane-bucket-` in the -{{< hover label="xr" line="5">}}$bucket{{}} variable. - -The {{< hover label="xr" line="8">}}spec.forProvider.region{{< /hover >}} tells -AWS which AWS region to use when deploying resources. +The {{< hover label="xr" line="9">}}spec.forProvider.region{{< /hover >}} tells +AWS which AWS region to use when deploying resources. -The region can be any +The region can be any [AWS Regional endpoint](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints) code. -Use `kubectl get buckets` to verify Crossplane created the bucket. +Use `kubectl -n crossplane-aws-app get buckets.s3.aws.m.upbound.io` to verify Crossplane created the bucket. {{< hint type="tip" >}} -Crossplane created the bucket when the values `READY` and `SYNCED` are `True`. -This may take up to 5 minutes. +Crossplane created the bucket when the values `READY` and `SYNCED` are `True`. +This may take up to 5 minutes. {{< /hint >}} ```shell {copy-lines="1"} -kubectl get buckets -NAME READY SYNCED EXTERNAL-NAME AGE -crossplane-bucket-hhdzh True True crossplane-bucket-hhdzh 5s +kubectl -n crossplane-aws-app get buckets.s3.aws.m.upbound.io +NAME SYNCED READY EXTERNAL-NAME AGE +crossplane-bucket-7tfcj True True crossplane-bucket-7tfcj 3m4s ``` ## Delete the managed resource Before shutting down your Kubernetes cluster, delete the S3 bucket just created. -Use `kubectl delete bucket ` to remove the bucket. +Use `kubectl -n crossplane-aws-app delete buckets.s3.aws.m.upbound.io ` to remove the bucket. ```shell {copy-lines="1"} -kubectl delete bucket crossplane-bucket-hhdzh -bucket.s3.aws.upbound.io "crossplane-bucket-hhdzh" deleted +kubectl -n crossplane-aws-app delete buckets.s3.aws.m.upbound.io crossplane-bucket-7tfcj +bucket.s3.aws.m.upbound.io "crossplane-bucket-7tfcj" deleted ``` +## Composing managed resources +Crossplane v2 allows you to compose **any type of resource** into custom APIs +for your users, which includes managed resources. Enjoy the freedom that +Crossplane v2 gives you to compose the diverse set of resources your +applications need for their unique environments, scenarios, and requirements. + +Follow [Get Started with Composition]({{}}) +to learn more about how composition works. + ## Next steps -* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with +* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with Crossplane users and contributors. From 30079d9e0e8ca4e6ea218a3f252a643e6560b6c6 Mon Sep 17 00:00:00 2001 From: Jared Watts Date: Thu, 27 Mar 2025 17:12:34 -0700 Subject: [PATCH 4/7] Streamline getting started with managed resources guide by removing fine grained details Signed-off-by: Jared Watts --- .../get-started-with-managed-resources.md | 36 +------------------ 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/content/v2.0-preview/get-started/get-started-with-managed-resources.md b/content/v2.0-preview/get-started/get-started-with-managed-resources.md index d7a0c727..96c9add5 100644 --- a/content/v2.0-preview/get-started/get-started-with-managed-resources.md +++ b/content/v2.0-preview/get-started/get-started-with-managed-resources.md @@ -134,26 +134,6 @@ generic aws-secret \ --from-file=creds=./aws-credentials.txt ``` -View the secret with `kubectl describe secret` - -{{< hint type="note" >}} -The size may be larger if there are extra blank spaces in your text file. -{{< /hint >}} - -```shell {copy-lines="1"} -kubectl describe secret aws-secret -n crossplane-system -Name: aws-secret -Namespace: crossplane-system -Labels: -Annotations: - -Type: Opaque - -Data -==== -creds: 114 bytes -``` - ## Create a ProviderConfig A {{< hover label="providerconfig" line="3">}}ProviderConfig{{}} customizes the settings of the AWS Provider. @@ -180,11 +160,6 @@ EOF This attaches the AWS credentials, saved as a Kubernetes secret, as a {{< hover label="providerconfig" line="9">}}secretRef{{}}. -The -{{< hover label="providerconfig" line="11">}}spec.credentials.secretRef.name{{< /hover >}} -value is the name of the Kubernetes secret containing the AWS credentials in the -{{< hover label="providerconfig" line="10">}}spec.credentials.secretRef.namespace{{< /hover >}}. - ## Create a namespace Before we can create our namespaced S3 bucket managed resource, we must create a namespace for it. @@ -214,19 +189,10 @@ spec: EOF ``` -The {{< hover label="xr" line="2">}}apiVersion{{< /hover >}} and -{{< hover label="xr" line="3">}}kind{{}} are from the provider's CRDs. - The {{< hover label="xr" line="6">}}metadata.generateName{{< /hover >}} gives a pattern that the provider will use to create a unique name for the bucket in S3. The generated name will look like `crossplane-bucket-`. -The {{< hover label="xr" line="9">}}spec.forProvider.region{{< /hover >}} tells -AWS which AWS region to use when deploying resources. - -The region can be any -[AWS Regional endpoint](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints) code. - Use `kubectl -n crossplane-aws-app get buckets.s3.aws.m.upbound.io` to verify Crossplane created the bucket. {{< hint type="tip" >}} @@ -241,7 +207,7 @@ crossplane-bucket-7tfcj True True crossplane-bucket-7tfcj 3m4s ``` ## Delete the managed resource -Before shutting down your Kubernetes cluster, delete the S3 bucket just created. +Before shutting down your Kubernetes cluster, delete the S3 bucket that was just created. Use `kubectl -n crossplane-aws-app delete buckets.s3.aws.m.upbound.io ` to remove the bucket. From 842a7c3163796104fd2e1cee0f8b57c617191a5a Mon Sep 17 00:00:00 2001 From: Jared Watts Date: Thu, 27 Mar 2025 19:26:17 -0700 Subject: [PATCH 5/7] incorporate PR feedback for get started with managed resources page Signed-off-by: Jared Watts --- .../get-started-with-managed-resources.md | 115 ++++++++---------- 1 file changed, 48 insertions(+), 67 deletions(-) diff --git a/content/v2.0-preview/get-started/get-started-with-managed-resources.md b/content/v2.0-preview/get-started/get-started-with-managed-resources.md index 96c9add5..414d5878 100644 --- a/content/v2.0-preview/get-started/get-started-with-managed-resources.md +++ b/content/v2.0-preview/get-started/get-started-with-managed-resources.md @@ -6,6 +6,10 @@ weight: 200 Connect Crossplane to AWS to create and manage cloud resources from Kubernetes with [provider-upjet-aws](https://github.com/crossplane-contrib/provider-upjet-aws). +A _managed resource_ is anything Crossplane creates and manages outside of the +control plane. + +This guide creates an AWS S3 bucket with Crossplane. The S3 bucket is a _managed resource_. ## Prerequisites This quickstart requires: @@ -15,50 +19,25 @@ This quickstart requires: * An AWS account with permissions to create an S3 storage bucket * AWS [access keys](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds) -## About Managed Resources in Crossplane v2 -A _managed resource_ is anything Crossplane creates and manages outside of the -Kubernetes cluster. - -This guide creates an AWS S3 bucket with Crossplane. - -The S3 bucket is a _managed resource_. - -Crossplane v2 allows you to compose namespaced resources. To better support this -new ability, managed resources (MRs) are now namespaced in Providers that have -been updated for Crossplane v2. - -To support backwards compatibility while users are adopting Crossplane v2, each -provider will offer the legacy cluster scoped MRs in addition to the new -namespaced MRs. - -For example, when the AWS provider that has been upated to support Crossplane v2 -is installed during this guide, you will see two CRDs for each type of managed -resource: - -1. A legacy cluster scoped MR in the `*.aws.upbound.io` API group -1. A namespaced MR in the `*.aws.m.upbound.io` API group - -{{< hint type="tip" >}} -More about namespaced managed resources can be read in the [Crossplane v2 proposal](https://github.com/crossplane/crossplane/pull/6255). -{{< /hint >}} - ## Install the AWS provider - Install the AWS S3 provider into the Kubernetes cluster with a Kubernetes configuration file. ```yaml {label="provider",copy-lines="all"} -cat <}}Provider{{}} +Save this to a file called `provider.yaml`, then apply it with: +```shell {label="kube-apply-provider",copy-lines="all"} +kubectl apply -f provider.yaml +``` + +The Crossplane {{< hover label="provider" line="2" >}}Provider{{}} installs the Kubernetes _Custom Resource Definitions_ (CRDs) representing AWS S3 services. These CRDs allow you to create AWS resources directly inside Kubernetes. @@ -81,7 +60,7 @@ Providers. You can view the new CRDs with `kubectl get crds`. Every CRD maps to a unique AWS service Crossplane can provision and manage. -{{< hint type="tip" >}} +{{< hint "tip" >}} See details about all the supported CRDs in the [provider examples](https://github.com/crossplane-contrib/provider-upjet-aws/tree/main/examples). {{< /hint >}} @@ -96,7 +75,7 @@ then configure the Provider to use it. ### Generate an AWS key-pair file For basic user authentication, use an AWS Access keys key-pair file. -{{< hint type="tip" >}} +{{< hint "tip" >}} The [AWS documentation](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds) provides information on how to generate AWS Access keys. {{< /hint >}} @@ -113,7 +92,7 @@ aws_secret_access_key = $@$@ Save this text file as `aws-credentials.txt`. -{{< hint type="note" >}} +{{< hint "note" >}} The [Authentication](https://docs.upbound.io/providers/provider-aws/authentication/) section of the AWS Provider documentation describes other authentication methods. {{< /hint >}} @@ -135,14 +114,10 @@ generic aws-secret \ ``` ## Create a ProviderConfig -A {{< hover label="providerconfig" line="3">}}ProviderConfig{{}} -customizes the settings of the AWS Provider. +A {{< hover label="providerconfig" line="2">}}ProviderConfig{{}} +customizes the settings of the AWS Provider: -Apply the -{{< hover label="providerconfig" line="3">}}ProviderConfig{{}} -with the this Kubernetes configuration file: ```yaml {label="providerconfig",copy-lines="all"} -cat <}}secretRef{{}}. - -## Create a namespace -Before we can create our namespaced S3 bucket managed resource, we must create a -namespace for it. +Save this to a file called `providerconfig.yaml`, then apply it with: -```shell {label="kube-create-namespace",copy-lines="all"} -kubectl create namespace crossplane-aws-app +```shell {label="kube-apply-providerconfig",copy-lines="all"} +kubectl apply -f providerconfig.yaml ``` +This attaches the AWS credentials, saved as a Kubernetes secret, as a +{{< hover label="providerconfig" line="8">}}secretRef{{}}. + ## Create a managed resource -{{< hint type="note" >}} +{{< hint "note" >}} AWS S3 bucket names must be globally unique. To generate a unique name the example uses a random hash. Any unique name is acceptable. {{< /hint >}} -```yaml {label="xr"} -cat <}}metadata.generateName{{< /hover >}} gives a -pattern that the provider will use to create a unique name for the bucket in S3. +Save this to a file called `bucket.yaml`, then apply it with: + +```shell {label="kube-create-bucket",copy-lines="all"} +kubectl create -f bucket.yaml +``` + +The {{< hover label="bucket" line="5">}}metadata.generateName{{< /hover >}} gives a +pattern that Kubernetes will use to create a unique name for the bucket in S3. The generated name will look like `crossplane-bucket-`. -Use `kubectl -n crossplane-aws-app get buckets.s3.aws.m.upbound.io` to verify Crossplane created the bucket. +Use `kubectl -n default get buckets.s3.aws.m.upbound.io` to verify Crossplane created the bucket. -{{< hint type="tip" >}} +{{< hint "tip" >}} Crossplane created the bucket when the values `READY` and `SYNCED` are `True`. This may take up to 5 minutes. {{< /hint >}} ```shell {copy-lines="1"} -kubectl -n crossplane-aws-app get buckets.s3.aws.m.upbound.io +kubectl -n default get buckets.s3.aws.m.upbound.io NAME SYNCED READY EXTERNAL-NAME AGE crossplane-bucket-7tfcj True True crossplane-bucket-7tfcj 3m4s ``` ## Delete the managed resource -Before shutting down your Kubernetes cluster, delete the S3 bucket that was just created. - -Use `kubectl -n crossplane-aws-app delete buckets.s3.aws.m.upbound.io ` to remove the bucket. +When you are finished with your S3 bucket, use `kubectl -n default +delete buckets.s3.aws.m.upbound.io ` to remove the bucket. ```shell {copy-lines="1"} -kubectl -n crossplane-aws-app delete buckets.s3.aws.m.upbound.io crossplane-bucket-7tfcj +kubectl -n default delete buckets.s3.aws.m.upbound.io crossplane-bucket-7tfcj bucket.s3.aws.m.upbound.io "crossplane-bucket-7tfcj" deleted ``` +{{< hint "important" >}} +Make sure to delete the S3 bucket before uninstalling the provider or shutting +down your control plane. If those are no longer running, they can't clean up any +managed resources and you would need to do so manually. +{{< /hint >}} + ## Composing managed resources -Crossplane v2 allows you to compose **any type of resource** into custom APIs -for your users, which includes managed resources. Enjoy the freedom that -Crossplane v2 gives you to compose the diverse set of resources your -applications need for their unique environments, scenarios, and requirements. +Crossplane allows you to compose **any type of resource** into custom APIs for +your users, which includes managed resources. Enjoy the freedom that Crossplane +gives you to compose the diverse set of resources your applications need for +their unique environments, scenarios, and requirements. Follow [Get Started with Composition]({{}}) to learn more about how composition works. From b7ec38492ffb800a51ef5c004de72e120b064edf Mon Sep 17 00:00:00 2001 From: Fabrice Brito Date: Fri, 28 Mar 2025 11:32:50 +0100 Subject: [PATCH 6/7] adds using secrets in a python function and cli --function-credentials --- content/master/cli/command-reference.md | 6 ++ .../write-a-composition-function-in-python.md | 69 +++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/content/master/cli/command-reference.md b/content/master/cli/command-reference.md index 95303420..be56a3ee 100644 --- a/content/master/cli/command-reference.md +++ b/content/master/cli/command-reference.md @@ -108,6 +108,7 @@ spec: | `-c` | `--include-context` | Include the context in the rendered output as a resource of kind: Context. | | `-x` | `--include-full-xr` | Include a copy of the input Composite Resource spec and metadata fields in the rendered output. | | | `--timeout=` | Amount of time to wait for a function to finish. (Default 1 minute) | +| | `--function-credentials=PATH` | A YAML file or directory of YAML files specifying credentials to use for Functions to render the XR. | {{< /table >}} @@ -127,6 +128,11 @@ If a function produces Kubernetes events with statuses use the `--include-function-results` to print them along with the managed resource outputs. +### Use a secret in a function + +If a function needs a secret, use the `--function-credentials=PATH` +where `PATH` is the path to a Kubernetes secret manifest. + ### Include the composite resource Composition functions can only change the `status` field of a composite diff --git a/content/master/guides/write-a-composition-function-in-python.md b/content/master/guides/write-a-composition-function-in-python.md index 58aad756..d54276cc 100644 --- a/content/master/guides/write-a-composition-function-in-python.md +++ b/content/master/guides/write-a-composition-function-in-python.md @@ -733,3 +733,72 @@ up continuous integration (CI) using lint, test, and build your function. You can see how the template configures CI by reading `.github/workflows/ci.yaml`. {{}} + +## Using credentials in the function + +To access a secret, the `composition.yaml` step declares it with: + +```yaml +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: create-buckets +spec: + compositeTypeRef: + apiVersion: example.crossplane.io/v1 + kind: XBuckets + mode: Pipeline + pipeline: + - step: create-buckets + credentials: + - name: function-credentials + secretRef: + name: secret-name + namespace: crossplane-system + source: Secret + functionRef: + name: function-xbuckets +``` + +Where `secret-name` is the kubernetes secret name. + +Edit the `RunFunction` method to read the credentials using `req.credentials`: + +{{}} +See [apiextensions.fn.proto.v1.RunFunctionRequest](https://buf.build/crossplane/crossplane/docs/main:apiextensions.fn.proto.v1#apiextensions.fn.proto.v1.RunFunctionRequest) +and [protobuf generated Python code ](https://protobuf.dev/reference/python/python-generated/) +to understand what kind of Python code is generated from the protobuf +and how to access the request content +{{}} + +```python +async def RunFunction(self, req: fnv1.RunFunctionRequest, _: grpc.aio.ServicerContext) -> fnv1.RunFunctionResponse: + log = self.log.bind(tag=req.meta.tag) + log.info("Running function") + + rsp = response.to(req) + + credentials = req.credentials + + username = credentials["secret-name"].credential_data.data["username"].decode("utf-8") + password = credentials["secret-name"].credential_data.data["password"].decode("utf-8") +``` + +To test the function with `crossplane render`, use: + +`crossplane render --function-credentials=secret.yaml xr.yaml composition.yaml functions.yaml` + +Where `secret.yaml` is a Kubernetes secret manifest: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: secret-name + namespace: crossplane-system +data: + username: bb..bb + password: aa..aa +type: Opaque +``` + From c15e516bae12d289cd124172bf8ae111cf678661 Mon Sep 17 00:00:00 2001 From: Fabrice Brito Date: Fri, 28 Mar 2025 11:32:50 +0100 Subject: [PATCH 7/7] adds using secrets in a python function and cli --function-credentials