Skip to content

Commit

Permalink
Merge pull request #134 from proactiveops/example
Browse files Browse the repository at this point in the history
Add example project
  • Loading branch information
skwashd authored Sep 2, 2024
2 parents 171e9ea + f1b3892 commit 0a751ff
Show file tree
Hide file tree
Showing 14 changed files with 30,955 additions and 28 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ The most common use case for using code bundles is to include pre and post proce

Out of the box PicoFun generates Lambda functions that make unauthenicated calls to endpoints. Often this isn't what teams need. The preprocessing and postprocessing hooks allow engineers to customize the request payload and response. A common use case for this is to add authentication headers to requests.

An example implementation of these hooks can be found in the [`examples/processors`](examples/processors) directory. The example pulls values from SSM Parameter store and adds them as authentication headers for the request. The postprocessor logs the request URL and response status code.
An example implementation of these hooks can be found in the [`example/zendesk_common`](example/zendesk_common) directory. The example pulls values from SSM Parameter store and uses them for the domain name and authorization header.

## Template Overrides

Expand All @@ -92,8 +92,6 @@ If you need to override one PicoFun template, you need to copy both from the pac

You can add the path to the templates to the `config.toml` file using the `template_path` entry.

An example implementation is included in the [`examples/templates`](examples/templates) directory. The example removes all logging and tracing support from the Lambda functions. This isn't recommended for real projects, but it provides a useful example of the feature.

## Terraform

PicoFun generates a terraform module to deploy the generated functions to AWS. The module is located in the root of your configured output directory. It `output`s the Lambda function ARNs and IAM role ARN.
Expand Down
93 changes: 93 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Zendesk Example

This example PicoFun project demonstrates generating Lambdas for the [Zendesk Ticketing API](https://developer.zendesk.com/api-reference/ticketing/introduction/).

## Setup

The project depends on two values being available in [SSM Parameter Store](https://www.davehall.com.au/blog/2021/02/22/parameter-store-vs-secrets-manager/). Add these values before deploying the project:

### `/picorun_zendesk/subdomain`

Set this as a type `String`, with a `text` data type. The value should be the subdomain of your Zendesk instance. If you access Zendesk via https://example.zendesk.com, then you would use `example` as the value. This is not a senstive value, so it doesn't need encrypting.

### `/picorun_zendesk/creds`

These are the credentials used to access your Zendesk instance. *These are sensitive values, so you must encrypt them.** Set the type to `SecureString`.

The IAM policy in `extra.tf` assumes that you're using the AWS managed key `alias/aws/ssm`. You can use a Customer Managed Key for encrypting the creds, but if you do so you will need to adjust the policy.

Set the value to `{"email":"[email]","token":"[token]"}`. Replace `[email]` with the email address of the agent or administrator who the Lambdas will act on behalf of. Use your [Zendesk API token](https://support.zendesk.com/hc/en-us/articles/4408889192858-Managing-access-to-the-Zendesk-API#topic_bsw_lfg_mmb) instead of `[token]`.

If my agent email address was [email protected] the JSON would look like so:

```json
{
"email": "[email protected]",
"token": "get_your_own_api_token_using_the_docs_linked_above"
}
```

## Generating Lambdas

To generate the Lambda functions and associated Terraform, run the following commmand:

```sh
picofun --config-file example/picofun.toml zendesk https://developer.zendesk.com/zendesk/oas.yaml
```
The output of the command should look something like this:

```
INFO:picofun.lambda_generator:Generated function: /path/to/picofun/output/lambdas/get_api_lotus_assignables_autocomplete_json.py
INFO:picofun.lambda_generator:Generated function: /path/to/picofun/output/lambdas/get_api_lotus_assignables_groups_json.py
[...]
INFO:picofun.lambda_generator:Generated function: /path/to/picofun/output/lambdas/delete_api_v2_workspaces_destroy_many.py
INFO:picofun.lambda_generator:Generated function: /path/to/picofun/output/lambdas/put_api_v2_workspaces_reorder.py
INFO:picofun.layer:Prepared layer contents: /path/to/picofun/output/layer
INFO:picofun.terraform_generator:Generated terraform: /path/to/picofun/output/main.tf
```

## Deployment

Before we deploy all of our Lambda functions we need to copy `extra.tf` to `output/` so we have the additional policy attached to the Lambdas execution role. This allows it to read the SSM params we created earlier. To do this, run:

```sh
cp example/extra.tf output
```

To run the deployment we need to change into the output directory by running:

```sh
cd output
```

Now we need to install the Terraform dependencies. We do that by running the following command:

```sh
terraform init
```

If you wish to restrict the versions of Terraform or the providers used, create a `providers.tf` file. Include the versions you wish to use. Copy this file into the output directory before runing `init`.

I assume you have your AWS credentials properly configured. If not, [do that now](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration).

**Finally** we're ready to deploy our Lambdas. To do this, run:

```
terraform apply
```

It will take a bit to calculate the change set. Wait for the confirmation prompt:

```
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value:
```

Review scrollback to ensure everything looks in order. When you're confident things look ok, type `yes` and hit [enter]. Go make a cup of tea, then bake a cake, make another cup of tea, eat the cake, drink both cups of tea, and then your lambda should have deployed.

## TODO

Create a GitHub Actions workflow for regenerating the functions on a weekly basis.
27 changes: 27 additions & 0 deletions example/extra.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}

data "aws_iam_policy_document" "ssm_read" {
statement {
sid = "SSMRead"
effect = "Allow"
resources = ["arn:aws:ssm:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:parameter/picorun_zendesk/*"]

actions = [
"ssm:GetParameter",
"ssm:GetParametersByPath",
"ssm:GetParameters",
]
}
}

resource "aws_iam_policy" "ssm_read" {
name = "pf-zendesk-ssm-read"
description = "Allow reading of SSM parameters"
policy = data.aws_iam_policy_document.ssm_read.json
}

resource "aws_iam_role_policy_attachment" "ssm_read" {
role = aws_iam_role.lambda.name
policy_arn = aws_iam_policy.ssm_read.arn
}
1 change: 1 addition & 0 deletions example/helpers/zendesk_common/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Example helpers module."""
24 changes: 24 additions & 0 deletions example/helpers/zendesk_common/preprocessor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Preprocessor for Zendesk API requests."""

import base64

import aws_lambda_powertools.utilities.parameters
import picorun


def preprocess(args: picorun.ApiRequestArgs) -> picorun.ApiRequestArgs:
"""Preprocess the request arguments."""
creds = aws_lambda_powertools.utilities.parameters.get_parameter(
"/picorun_zendesk/creds", max_age=60, decrypt=True, transform="json"
)
auth = base64.b64encode(
f"{creds['email']}/token:{creds['token']}".encode()
).decode()
args.headers["Authorization"] = f"Basic {auth}"

subdomain = aws_lambda_powertools.utilities.parameters.get_parameter(
"/picorun_zendesk/subdomain", max_age=60
)
args.path["subdomain"] = subdomain
args.path["domain"] = "zendesk"
return args
7 changes: 7 additions & 0 deletions example/picofun.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
bundle = "helpers"
preprocessor = "zendesk_common.preprocessor.preprocess"
layers = ["arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:79"]

[tags]
app = "picofun-zendesk"
env = "poc"
Loading

0 comments on commit 0a751ff

Please sign in to comment.