Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/issue 205 - Add Confluence API key #221

Merged
merged 14 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ concurrency:
env:
POETRY_VERSION: "1.7.1"
PYTHON_VERSION: "3.10"
TERRAFORM_VERSION: "1.7.3"
TERRAFORM_VERSION: "1.9.3"
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- Issue 205 - Define a an API key for the Confluence workflow and usage plan limits
- Issue 201- Create table for tracking granule ingest status
- Issue 198 - Implement track ingest lambda function CMR and Hydrocron queries
- Issue 193 - Add new Dynamo table for prior lake data
Expand Down
7 changes: 2 additions & 5 deletions docs/timeseries.md
Original file line number Diff line number Diff line change
Expand Up @@ -444,12 +444,9 @@ Example CSV response:

*The 400 code is also currently returned for queries where no time series data could be located for the request specified feature ID. The message returned with the response indicates this and it can be helpful to adjust the date ranges you are searching.

## API Keys [DRAFT]
## API Keys

> ⚠️
>API keys not yet implemented but coming soon! Content below is not finalized. More details to follow...

Users may request a special API key for cases where their intended usage of the API may be considered heavy or more complex. Heavy usage can be defined as continued used with over x requests per day or continue use which require many requests per second or concurrent requests. To request an API key or to discuss your use case, please contact us at x.
Users may request a special API key for cases where their intended usage of the API may be considered heavy or more complex. Heavy usage can be defined as continued use with many requests per hour or day or continued use which may require many requests per second or concurrent requests. To request an API key or to discuss your use case, please submit a [GitHub issue](https://github.com/podaac/hydrocron/issues).

**Note: Users do *not* have to send an API key in their request to use the Hydrocron API. The API key is optional.**

Expand Down
5 changes: 3 additions & 2 deletions hydrocron/api/controllers/authorizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ def authorization_handler(event, context):
logging.info("Context: %s", context)

api_key_trusted = "" if "x-hydrocron-key" not in event["headers"].keys() else event["headers"]["x-hydrocron-key"]
trusted_key_list = json.loads(STORED_API_KEY_TRUSTED)

if api_key_trusted and api_key_trusted == STORED_API_KEY_TRUSTED:
response_policy = create_policy("trusted_partner", "Allow", event["methodArn"], STORED_API_KEY_TRUSTED)
if api_key_trusted and api_key_trusted in trusted_key_list:
response_policy = create_policy("trusted_partner", "Allow", event["methodArn"], api_key_trusted)
logging.info("Created policy for truster partner.")

else:
Expand Down
1 change: 0 additions & 1 deletion terraform/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 15 additions & 10 deletions terraform/hydrocron-apigw.tf
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ resource "aws_api_gateway_api_key" "default-user-key" {
}


resource "aws_api_gateway_api_key" "trusted-user-key" {
name = "${local.aws_resource_prefix}-api-key-trusted"
resource "aws_api_gateway_api_key" "confluence-user-key" {
name = "${local.aws_resource_prefix}-api-key-confluence"
}


Expand All @@ -124,7 +124,11 @@ resource "aws_ssm_parameter" "trusted-user-parameter" {
name = "/service/${var.app_name}/api-key-trusted"
description = "Hydrocron trusted user API key"
type = "SecureString"
value = aws_api_gateway_api_key.trusted-user-key.value
value = jsonencode(
[
"${aws_api_gateway_api_key.confluence-user-key.value}"
]
)
}


Expand All @@ -146,14 +150,14 @@ resource "aws_api_gateway_usage_plan" "default-user-usage-plan" {
}
}


resource "aws_api_gateway_usage_plan_key" "default-user-usage-key" {
key_id = aws_api_gateway_api_key.default-user-key.id
key_type = "API_KEY"
usage_plan_id = aws_api_gateway_usage_plan.default-user-usage-plan.id
}



resource "aws_api_gateway_usage_plan" "trusted-user-usage-plan" {
name = "${local.aws_resource_prefix}-usage-plan-trusted"
description = "Hydrocron trusted user usage plan"
Expand All @@ -162,17 +166,18 @@ resource "aws_api_gateway_usage_plan" "trusted-user-usage-plan" {
stage = aws_api_gateway_stage.hydrocron-api-gateway-stage.stage_name
}
quota_settings {
limit = 5
limit = 12107815
period = "MONTH"
}
throttle_settings {
burst_limit = 1
rate_limit = 1
burst_limit = 3000
rate_limit = 6000
}
}

resource "aws_api_gateway_usage_plan_key" "trusted-user-usage-key" {
key_id = aws_api_gateway_api_key.trusted-user-key.id

resource "aws_api_gateway_usage_plan_key" "confluence-user-usage-key" {
key_id = aws_api_gateway_api_key.confluence-user-key.id
key_type = "API_KEY"
usage_plan_id = aws_api_gateway_usage_plan.trusted-user-usage-plan.id
}
}
6 changes: 3 additions & 3 deletions terraform/hydrocron-dynamo.tf
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ resource "aws_dynamodb_table" "hydrocron-track-ingest-table" {
type = "S"
}
global_secondary_index {
name = "statusIndex"
hash_key = "status"
projection_type = "ALL"
name = "statusIndex"
hash_key = "status"
projection_type = "ALL"
}
point_in_time_recovery {
enabled = var.stage == "ops" ? true : false
Expand Down
19 changes: 18 additions & 1 deletion terraform/hydrocron-lambda.tf
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ resource "aws_lambda_permission" "allow_hydrocron-timeseries" {
source_arn = "${aws_api_gateway_rest_api.hydrocron-api-gateway.execution_arn}/*"
}

resource "null_resource" "api_key_hash" {
/**
This resource is needed because of https://github.com/podaac/hydrocron/issues/205#issuecomment-2250982988
*/
triggers = {
default_key = aws_ssm_parameter.default-user-parameter.value
trusted_key_list = aws_ssm_parameter.trusted-user-parameter.value
}
}

resource "aws_lambda_function" "hydrocron_lambda_authorizer" {
package_type = "Image"
Expand All @@ -98,6 +107,14 @@ resource "aws_lambda_function" "hydrocron_lambda_authorizer" {
security_group_ids = data.aws_security_groups.vpc_default_sg.ids
}
tags = var.default_tags

/**
This is the preferred solution in lieu of the nonsense below but when using replace_triggered_by, terraform plan fails
to replace the lambda correctly and results in an error "ResourceConflictException: Function already exist"

lifecycle { replace_triggered_by = [aws_ssm_parameter.default-user-parameter.value, aws_ssm_parameter.trusted-user-parameter.value]}
*/
source_code_hash = null_resource.api_key_hash.id
}


Expand Down Expand Up @@ -201,4 +218,4 @@ resource "aws_lambda_function" "hydrocron_lambda_track_ingest" {
GRANULE_LAMBDA_FUNCTION_NAME = aws_lambda_function.hydrocron_lambda_load_granule.function_name
}
}
}
}
2 changes: 1 addition & 1 deletion terraform/versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ terraform {
required_providers {
aws = "~> 4.0"
}
required_version = ">= 1.7.3"
required_version = ">= 1.9.3"
}
3 changes: 1 addition & 2 deletions tests/test_authorizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ def setUp(self):
# Create SSM client and put API keys
ssm = boto3.client("ssm")
ssm.put_parameter(Name="/service/hydrocron/api-key-default", Value="abc123", Type="SecureString")
ssm.put_parameter(Name="/service/hydrocron/api-key-trusted", Value="def456", Type="SecureString")
ssm.put_parameter(Name="/service/hydrocron/api-key-trusted", Value='["def456", "qrs789"]', Type="SecureString")

def tearDown(self):

self.mock_aws.stop()


def test_authorizer_lambda_handler_default(self):
"""
Expand Down
5 changes: 2 additions & 3 deletions tests/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ def test_s3_resource(s3_connection):
# Import module
from hydrocron.utils import connection
assert type(connection.s3_resource).__name__ == "s3.ServiceResource"



def test_ssm_client():
"""Test retrieval of DynamoDB resource."""

# Import module
from hydrocron.utils import connection
assert type(connection.ssm_client).__name__ == "SSM"
assert type(connection.ssm_client).__name__ == "SSM"
4 changes: 1 addition & 3 deletions tests/test_data/api_authorizer_default.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
"resource": "/timeseries",
"path": "/timeseries",
"httpMethod": "GET",
"headers": {
"x-api-key": "abc123"
},
"headers": {},
"pathParameters": {},
"stageVariables": {},
"requestContext": {
Expand Down