Skip to content

Commit

Permalink
Merge pull request #3 from aws-ia/v0.0.1
Browse files Browse the repository at this point in the history
V0.0.1
  • Loading branch information
tbulding authored Aug 27, 2024
2 parents 7d08228 + bd4f014 commit acbbea3
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 7 deletions.
12 changes: 12 additions & 0 deletions .header.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,19 @@ Integrate Amazon Bedrock to your HashiCorp Cloud Platform Terraform (Terraform C

### Terraform plan summary

Summarize Terraform plan output in human friendly natural language.
![Example](./images/example.png)

### Function calling (AMI analysis)

Use function calling to execute other tools, such as analyzing AMI data.
![Example2](./images/example2.png)

### Responsible AI

Implement safeguards using Amazon Bedrock guardrails customized to your organization requirements and responsible AI policies
![Example3](./images/example3.png)

## Architecture

![Diagram](./images/arch.png)
Expand All @@ -29,6 +36,7 @@ Please refer to the [best-practice](#best-practice) section below for more detai
To use this module you need have the following:

1. AWS account and credentials
1. Amazon Bedrock model access (default model is `Claude 3 Sonnet`)
1. HCP Terraform account

## Usage
Expand All @@ -39,6 +47,8 @@ To use this module you need have the following:
make all
```

* Enable Bedrock model access for `Claude 3 Sonnet`. Refer to [this guide for more info](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html).

* Reference the `examples/basic` folder on how to use this module

```sh
Expand All @@ -57,3 +67,5 @@ To use this module you need have the following:
* Enable the AWS WAF setup by setting variable `deploy_waf` to `true` (additional cost will apply). This will add WAF protection to the Run Tasks URL endpoint.

* We recommend you to setup additional CloudWatch alarm to monitor Lambda concurrency and WAF rules.

* We recommend to add additional topic to the Bedrock Guardrail to fit your organization requirements.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@ Integrate Amazon Bedrock to your HashiCorp Cloud Platform Terraform (Terraform C

### Terraform plan summary

Summarize Terraform plan output in human friendly natural language.
![Example](./images/example.png)

### Function calling (AMI analysis)

Use function calling to execute other tools, such as analyzing AMI data.
![Example2](./images/example2.png)

### Responsible AI

Implement safeguards using Amazon Bedrock guardrails customized to your organization requirements and responsible AI policies
![Example3](./images/example3.png)

## Architecture

![Diagram](./images/arch.png)
Expand All @@ -30,6 +37,7 @@ Please refer to the [best-practice](#best-practice) section below for more detai
To use this module you need have the following:

1. AWS account and credentials
1. Amazon Bedrock model access (default model is `Claude 3 Sonnet`)
1. HCP Terraform account

## Usage
Expand All @@ -40,6 +48,8 @@ To use this module you need have the following:
make all
```

* Enable Bedrock model access for `Claude 3 Sonnet`. Refer to [this guide for more info](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html).

* Reference the `examples/basic` folder on how to use this module

```sh
Expand All @@ -59,13 +69,16 @@ To use this module you need have the following:

* We recommend you to setup additional CloudWatch alarm to monitor Lambda concurrency and WAF rules.

* We recommend to add additional topic to the Bedrock Guardrail to fit your organization requirements.

## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.5.0 |
| <a name="requirement_archive"></a> [archive](#requirement\_archive) | ~>2.2.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.47.0 |
| <a name="requirement_awscc"></a> [awscc](#requirement\_awscc) | >= 1.11.0 |
| <a name="requirement_random"></a> [random](#requirement\_random) | >=3.4.0 |

## Providers
Expand All @@ -75,6 +88,7 @@ To use this module you need have the following:
| <a name="provider_archive"></a> [archive](#provider\_archive) | ~>2.2.0 |
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.47.0 |
| <a name="provider_aws.cloudfront_waf"></a> [aws.cloudfront\_waf](#provider\_aws.cloudfront\_waf) | >= 5.47.0 |
| <a name="provider_awscc"></a> [awscc](#provider\_awscc) | >= 1.11.0 |
| <a name="provider_random"></a> [random](#provider\_random) | >=3.4.0 |
| <a name="provider_terraform"></a> [terraform](#provider\_terraform) | n/a |
| <a name="provider_time"></a> [time](#provider\_time) | n/a |
Expand Down Expand Up @@ -136,6 +150,8 @@ To use this module you need have the following:
| [aws_sfn_state_machine.runtask_states](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sfn_state_machine) | resource |
| [aws_wafv2_web_acl.runtask_waf](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl) | resource |
| [aws_wafv2_web_acl_logging_configuration.runtask_waf](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl_logging_configuration) | resource |
| [awscc_bedrock_guardrail.runtask_fulfillment](https://registry.terraform.io/providers/hashicorp/awscc/latest/docs/resources/bedrock_guardrail) | resource |
| [awscc_bedrock_guardrail_version.runtask_fulfillment](https://registry.terraform.io/providers/hashicorp/awscc/latest/docs/resources/bedrock_guardrail_version) | resource |
| [random_string.solution_prefix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource |
| [random_uuid.runtask_cloudfront](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/uuid) | resource |
| [random_uuid.runtask_hmac](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/uuid) | resource |
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.0.0
v0.0.1
92 changes: 92 additions & 0 deletions bedrock.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
resource "awscc_bedrock_guardrail" "runtask_fulfillment" {
name = "${local.solution_prefix}-guardrail"
blocked_input_messaging = "Unfortunately we are unable to provide response for this input"
blocked_outputs_messaging = "Unfortunately we are unable to provide response for this input"
description = "Basic Bedrock Guardrail for sensitive info exfiltration"

# detect and filter harmful user inputs and FM-generated outputs
content_policy_config = {
filters_config = [
{
input_strength = "HIGH"
output_strength = "HIGH"
type = "SEXUAL"
},
{
input_strength = "HIGH"
output_strength = "HIGH"
type = "VIOLENCE"
},
{
input_strength = "HIGH"
output_strength = "HIGH"
type = "HATE"
},
{
input_strength = "HIGH"
output_strength = "HIGH"
type = "INSULTS"
},
{
input_strength = "HIGH"
output_strength = "HIGH"
type = "MISCONDUCT"
},
{
input_strength = "NONE"
output_strength = "NONE"
type = "PROMPT_ATTACK"
}
]
}

# block / mask potential PII information
sensitive_information_policy_config = {
pii_entities_config = [
{
action = "BLOCK"
type = "DRIVER_ID"
},
{
action = "BLOCK"
type = "PASSWORD"
},
{
action = "ANONYMIZE"
type = "EMAIL"
},
{
action = "ANONYMIZE"
type = "USERNAME"
},
{
action = "BLOCK"
type = "AWS_ACCESS_KEY"
},
{
action = "BLOCK"
type = "AWS_SECRET_KEY"
},
]
}

# block select word / profanity
word_policy_config = {
managed_word_lists_config = [{
type = "PROFANITY"
}]
}

tags = [for k, v in local.combined_tags :
{
key : k,
value : v
}
]

}

resource "awscc_bedrock_guardrail_version" "runtask_fulfillment" {
guardrail_identifier = awscc_bedrock_guardrail.runtask_fulfillment.guardrail_id
description = "Initial version"
}
2 changes: 1 addition & 1 deletion examples/basic/.header.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Usage Example

Follow the steps below to deploy the module and attach it to your Terraform Cloud organization.
Follow the steps below to deploy the module and attach it to your HCP Terraform (Terraform Cloud) organization.

* Build and package the Lambda files

Expand Down
2 changes: 1 addition & 1 deletion examples/basic/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!-- BEGIN_TF_DOCS -->
# Usage Example

Follow the steps below to deploy the module and attach it to your Terraform Cloud organization.
Follow the steps below to deploy the module and attach it to your HCP Terraform (Terraform Cloud) organization.

* Build and package the Lambda files

Expand Down
Binary file added images/example3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions lambda.tf
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,10 @@ resource "aws_lambda_function" "runtask_fulfillment" {
}
environment {
variables = {
CW_LOG_GROUP_NAME = local.cloudwatch_log_group_name
BEDROCK_LLM_MODEL = var.bedrock_llm_model
CW_LOG_GROUP_NAME = local.cloudwatch_log_group_name
BEDROCK_LLM_MODEL = var.bedrock_llm_model
BEDROCK_GUARDRAIL_ID = awscc_bedrock_guardrail.runtask_fulfillment.guardrail_id
BEDROCK_GUARDRAIL_VERSION = awscc_bedrock_guardrail_version.runtask_fulfillment.version
}
}
tags = local.combined_tags
Expand Down
55 changes: 53 additions & 2 deletions lambda/runtask_fulfillment/ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# Initialize model_id and region
default_model_id = "anthropic.claude-3-sonnet-20240229-v1:0"
model_id = os.environ.get("BEDROCK_LLM_MODEL", default_model_id)
guardrail_id = os.environ.get("BEDROCK_GUARDRAIL_ID", None)
guardrail_version = os.environ.get("BEDROCK_GUARDRAIL_VERSION", None)

# Config to avoid timeouts when using long prompts
config = botocore.config.Config(
Expand Down Expand Up @@ -207,6 +209,55 @@ def eval(tf_plan_json):
logger.info("Terraform plan summary: {}".format(description))

results = []
results.append(generate_runtask_result(outcome_id="Plan-Summary", description="Summary of Terraform plan", result=description[:700]))
results.append(generate_runtask_result(outcome_id="AMI-Summary", description="Summary of AMI changes", result=result[:700]))

guardrail_status, guardrail_response = guardrail_inspection(str(description))
if guardrail_status:
results.append(generate_runtask_result(outcome_id="Plan-Summary", description="Summary of Terraform plan", result=description[:700]))
else:
results.append(generate_runtask_result(outcome_id="Plan-Summary", description="Summary of Terraform plan", result="Output omitted due to : {}".format(guardrail_response)))
description = "Bedrock guardrail triggered : {}".format(guardrail_response)

guardrail_status, guardrail_response = guardrail_inspection(str(result))
if guardrail_status:
results.append(generate_runtask_result(outcome_id="AMI-Summary", description="Summary of AMI changes", result=result[:700]))
else:
results.append(generate_runtask_result(outcome_id="AMI-Summary", description="Summary of AMI changes", result="Output omitted due to : {}".format(guardrail_response)))

return description, results

def guardrail_inspection(input_text, input_mode = 'OUTPUT'):

#####################################################################
##### Inspect input / output against Bedrock Guardrail #####
#####################################################################

if guardrail_id and guardrail_version:
logger.info("##### Scanning Terraform plan output with Amazon Bedrock Guardrail #####")

response = bedrock_client.apply_guardrail(
guardrailIdentifier=guardrail_id,
guardrailVersion=guardrail_version,
source=input_mode,
content=[
{
'text': {
'text': input_text,
}
},
]
)

logger.debug("Guardrail inspection result : {}".format(json.dumps(response)))

if response["action"] in ["GUARDRAIL_INTERVENED"]:
logger.info("Guardrail action : {}".format(response["action"]))
logger.info("Guardrail output : {}".format(response["outputs"]))
logger.debug("Guardrail assessments : {}".format(response["assessments"]))
return False, response["outputs"][0]["text"]

elif response["action"] in ["NONE"]:
logger.info("No Guardrail action required")
return True, "No Guardrail action required"

else:
return True, "Guardrail inspection skipped"
4 changes: 4 additions & 0 deletions providers.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ terraform {
source = "hashicorp/aws"
version = ">= 5.47.0"
}
awscc = {
source = "hashicorp/awscc"
version = ">= 1.11.0"
}
random = {
source = "hashicorp/random"
version = ">=3.4.0"
Expand Down

0 comments on commit acbbea3

Please sign in to comment.