Skip to content

Commit

Permalink
Merge pull request #3 from MeltanoLabs/auth_refactor
Browse files Browse the repository at this point in the history
refactor: Auth refactor
  • Loading branch information
pnadolny13 authored Apr 11, 2023
2 parents 551d8ac + 72d4fe7 commit bcb3d97
Show file tree
Hide file tree
Showing 9 changed files with 366 additions and 130 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,4 @@ dmypy.json

# Pyre type checker
.pyre/
.vscode/launch.json
.vscode/*
76 changes: 27 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,37 @@
# tap-dynamodb
# `tap-dynamodb`

`tap-dynamodb` is a Singer tap for DynamoDB.
DynamoDB tap class.

Built with the [Meltano Tap SDK](https://sdk.meltano.com) for Singer Taps.
Built with the [Meltano Singer SDK](https://sdk.meltano.com).

<!--
## Capabilities

Developer TODO: Update the below as needed to correctly describe the install procedure. For instance, if you do not have a PyPi repo, or if you want users to directly install from your git repo, you can modify this step as appropriate.
* `catalog`
* `state`
* `discover`
* `about`
* `stream-maps`
* `schema-flattening`

## Installation
## Settings

Install from PyPi:
| Setting | Required | Default | Description |
|:---------------------|:--------:|:-------:|:------------|
| aws_access_key_id | False | None | The access key for your AWS account. |
| aws_secret_access_key| False | None | The secret key for your AWS account. |
| aws_session_token | False | None | The session key for your AWS account. This is only needed when you are using temporary credentials. |
| aws_profile | False | None | The AWS credentials profile name to use. The profile must be configured and accessible. |
| aws_default_region | False | None | The default AWS region name (e.g. us-east-1) |
| aws_endpoint_url | False | None | The complete URL to use for the constructed client. |
| aws_assume_role_arn | False | None | The role ARN to assume. |
| use_aws_env_vars | False | 0 | Whether to retrieve aws credentials from environment variables. |
| tables | False | None | An array of table names to extract from. |
| stream_maps | False | None | Config object for stream maps capability. For more information check out [Stream Maps](https://sdk.meltano.com/en/latest/stream_maps.html). |
| stream_map_config | False | None | User-defined config values to be used within map expressions. |
| flattening_enabled | False | None | 'True' to enable schema flattening and automatically expand nested properties. |
| flattening_max_depth | False | None | The max depth to flatten schemas. |

```bash
pipx install tap-dynamodb
```
Install from GitHub:
```bash
pipx install git+https://github.com/ORG_NAME/tap-dynamodb.git@main
```
-->

## Configuration

### Accepted Config Options

<!--
Developer TODO: Provide a list of config options accepted by the tap.
This section can be created by copy-pasting the CLI output from:
```
tap-dynamodb --about --format=markdown
```
-->

A full list of supported settings and capabilities for this
tap is available by running:

```bash
tap-dynamodb --about
```
A full list of supported settings and capabilities is available by running: `tap-dynamodb --about`

### Configure using environment variables

Expand All @@ -53,10 +41,6 @@ environment variable is set either in the terminal context or in the `.env` file

### Source Authentication and Authorization

<!--
Developer TODO: If your tap requires special access on the source system, or any special authentication requirements, provide those here.
-->

## Usage

You can easily run `tap-dynamodb` by itself or in a pipeline using [Meltano](https://meltano.com/).
Expand Down Expand Up @@ -108,12 +92,6 @@ poetry run tap-dynamodb --help
_**Note:** This tap will work in any Singer environment and does not require Meltano.
Examples here are for convenience and to streamline end-to-end orchestration scenarios._

<!--
Developer TODO:
Your project comes with a custom `meltano.yml` project file already created. Open the `meltano.yml` and follow any "TODO" items listed in
the file.
-->

Next, install Meltano (if you haven't already) and any needed plugins:

```bash
Expand Down
63 changes: 56 additions & 7 deletions meltano.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,64 @@ plugins:
- discover
- about
- stream-maps
config:
start_date: '2010-01-01T00:00:00Z'
- schema-flattening
settings:
# TODO: To configure using Meltano, declare settings and their types here:
- name: username
- name: password
- name: aws_access_key_id
label: AWS Access Key ID
description: The access key for your AWS account.
kind: password
- name: start_date
value: '2010-01-01T00:00:00Z'
- name: aws_secret_access_key
label: AWS Secret Access Key
description: The secret key for your AWS account.
kind: password
- name: aws_session_token
label: AWS Session Token
description: The session key for your AWS account. This is only needed when you
are using temporary credentials.
kind: password
- name: aws_profile
label: AWS Profile
description: The AWS credentials profile name to use. The profile must be configured
and accessible.
kind: string
- name: aws_default_region
label: AWS Default Region
description: 'The default AWS region name (e.g. us-east-1) '
kind: string
- name: aws_endpoint_url
label: AWS Endpoint URL
description: The complete URL to use for the constructed client.
kind: string
- name: aws_assume_role_arn
label: AWS Assume Role Arn
description: The role ARN to assume.
kind: string
- name: use_aws_env_vars
label: Use AWS Env Vars
description: Whether to retrieve aws credentials from environment variables.
kind: boolean
- name: tables
label: Tables
description: An array of table names to extract from.
kind: array
- name: stream_maps
label: Stream Maps
description: Config object for stream maps capability. For more information check
out [Stream Maps](https://sdk.meltano.com/en/latest/stream_maps.html).
kind: object
- name: stream_map_config
label: Stream Map Config
description: User-defined config values to be used within map expressions.
kind: object
- name: flattening_enabled
label: Flattening Enabled
description: "'True' to enable schema flattening and automatically expand nested\
\ properties."
kind: boolean
- name: flattening_max_depth
label: Flattening Max Depth
description: The max depth to flatten schemas.
kind: integer
loaders:
- name: target-jsonl
variant: andyh1203
Expand Down
91 changes: 91 additions & 0 deletions tap_dynamodb/aws_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import logging
import os

import boto3


class AWSAuth:
def __init__(self, config):
# config for use environment variables
if config.get("use_aws_env_vars"):
self.aws_access_key_id = os.environ.get("AWS_ACCESS_KEY_ID")
self.aws_secret_access_key = os.environ.get("AWS_SECRET_ACCESS_KEY")
self.aws_session_token = os.environ.get("AWS_SESSION_TOKEN")
self.aws_profile = os.environ.get("AWS_PROFILE")
self.aws_default_region = os.environ.get("AWS_DEFAULT_REGION")
else:
self.aws_access_key_id = config.get("aws_access_key_id")
self.aws_secret_access_key = config.get("aws_secret_access_key")
self.aws_session_token = config.get("aws_session_token")
self.aws_profile = config.get("aws_profile")
self.aws_default_region = config.get("aws_default_region")

self.aws_endpoint_url = config.get("aws_endpoint_url")
self.aws_assume_role_arn = config.get("aws_assume_role_arn")

self.logger = logging.getLogger(__name__)

def get_session(self):
session = None
if (
self.aws_access_key_id
and self.aws_secret_access_key
and self.aws_session_token
and self.aws_default_region
):
session = boto3.Session(
aws_access_key_id=self.aws_access_key_id,
aws_secret_access_key=self.aws_secret_access_key,
aws_session_token=self.aws_session_token,
region_name=self.aws_default_region,
)
elif (
self.aws_access_key_id
and self.aws_secret_access_key
and self.aws_default_region
):
session = boto3.Session(
aws_access_key_id=self.aws_access_key_id,
aws_secret_access_key=self.aws_secret_access_key,
region_name=self.aws_default_region,
)
elif self.aws_profile:
session = boto3.Session(profile_name=self.aws_profile)
self.logger.info("Using installed shared credentials file.")
else:
raise Exception("Explicit AWS auth not provided")

if self.aws_assume_role_arn:
if not session:
raise Exception("Insufficient inputs for AWS Auth.")
session = self._assume_role(session, self.aws_assume_role_arn)
return session

def _factory(self, aws_obj, service_name):
if self.aws_endpoint_url:
return aws_obj(
service_name,
endpoint_url=self.aws_endpoint_url,
)
else:
return aws_obj(
service_name,
)

def get_resource(self, session, service_name):
return self._factory(session.resource, service_name)

def get_client(self, session, service_name):
return self._factory(session.client, service_name)

def _assume_role(self, session, role_arn):
# TODO: use for auto refresh https://github.com/benkehoe/aws-assume-role-lib
sts_client = self.get_client(session, "sts")
response = sts_client.assume_role(
RoleArn=role_arn, RoleSessionName="tap-dynamodb"
)
return boto3.Session(
aws_access_key_id=response["Credentials"]["AccessKeyId"],
aws_secret_access_key=response["Credentials"]["SecretAccessKey"],
aws_session_token=response["Credentials"]["SessionToken"],
)
32 changes: 32 additions & 0 deletions tap_dynamodb/aws_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import logging

from tap_dynamodb.aws_auth import AWSAuth


class AWSBase:
def __init__(self, config, service_name):
self._service_name = service_name
self._config = config
self._client = None
self._resource = None
self.logger = logging.getLogger(__name__)

@property
def client(self):
if self._client:
return self._client
else:
auth_obj = AWSAuth(self._config)
session = auth_obj.get_session()
self._client = auth_obj.get_client(session, self._service_name)
return self._client

@property
def resource(self):
if self._resource:
return self._resource
else:
auth_obj = AWSAuth(self._config)
session = auth_obj.get_session()
self._resource = auth_obj.get_resource(session, self._service_name)
return self._resource
Loading

0 comments on commit bcb3d97

Please sign in to comment.