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

Add IAM Role Authentication #781

Merged
merged 76 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
d4e05f6
adding SSO support for redshift
abbywh Oct 16, 2023
a8ceb84
ADAP-891: Support test results as views (#614)
mikealfare Oct 10, 2023
48128e2
Use the PID to terminate the session (#568)
dbeatty10 Oct 11, 2023
dcc87c4
added error checking for new optional user field
abbywh Oct 16, 2023
a8a9118
Merge branch 'main' into Feature/iamr_auth
colin-rogers-dbt Oct 16, 2023
a60743c
black formatting
abbywh Oct 19, 2023
3b8ad21
Merge branch 'main' into Feature/iamr_auth
colin-rogers-dbt Oct 23, 2023
f657c94
Merge branch 'main' into Feature/iamr_auth
colin-rogers-dbt Nov 4, 2023
c6f02be
Merge branch 'main' into Feature/iamr_auth
dataders Nov 21, 2023
d574ef4
Merge branch 'main' into Feature/iamr_auth
mikealfare Apr 11, 2024
1175207
move connection fixtures into the functional scope
mikealfare Apr 16, 2024
d85f503
add iam user creds to the test.env template
mikealfare Apr 16, 2024
4255abe
add test for database connection method
mikealfare Apr 16, 2024
6eaa5ea
add iam user auth test
mikealfare Apr 18, 2024
8addeea
Merge branch 'refs/heads/main' into iam-auth
mikealfare Apr 19, 2024
736fd1e
add IAM User auth test and second user auth method
mikealfare Apr 19, 2024
effdb6b
changie
mikealfare Apr 19, 2024
6d57662
Merge branch 'main' into iam-auth
mikealfare Apr 19, 2024
4c3dd3f
maintain existing behavior when not providing profile
mikealfare Apr 19, 2024
9a08786
Merge remote-tracking branch 'origin/iam-auth' into iam-auth
mikealfare Apr 19, 2024
f87601f
add AWS IAM profile
mikealfare Apr 19, 2024
d55b6ee
pull in new env vars
mikealfare Apr 19, 2024
0501c53
fixed env vars refs for CI
mikealfare Apr 19, 2024
f3697a7
move all repo vars to secrets
mikealfare Apr 19, 2024
e97a2f6
Merge branch 'refs/heads/main' into iam-auth
mikealfare Apr 23, 2024
dbeb882
split out connect method by connection method and provided information
mikealfare Apr 23, 2024
1f64811
condition to produce just kwargs, consolidate connect method
mikealfare Apr 23, 2024
228e318
update .format to f-strings
mikealfare Apr 23, 2024
232db28
merge abbywh changes into iam-auth
mikealfare Apr 23, 2024
129ad1c
incorporate feedback from pr#630
mikealfare Apr 23, 2024
4911b53
update kwargs logic flow
mikealfare Apr 23, 2024
12b7239
updates to make space for iam role
mikealfare Apr 23, 2024
03771aa
Merge branch 'refs/heads/iam-auth' into iam-role-auth
mikealfare Apr 23, 2024
2f8de9e
revert type on user
mikealfare Apr 23, 2024
f7c5b3e
revert test case decorator
mikealfare Apr 23, 2024
a7dc038
revert test case decorator
mikealfare Apr 23, 2024
71a5797
revert error message
mikealfare Apr 23, 2024
434a950
add integration tests
mikealfare Apr 23, 2024
8336788
make space for both iam user and iam role in testing
mikealfare Apr 23, 2024
5c8bea7
Merge branch 'refs/heads/main' into iam-auth
mikealfare Apr 23, 2024
62a43bd
Merge branch 'refs/heads/iam-auth' into iam-role-auth
mikealfare Apr 23, 2024
621aa7c
add role arn
mikealfare Apr 24, 2024
b72a42e
naming
mikealfare Apr 24, 2024
57f85a4
try supplying region for CI
mikealfare Apr 24, 2024
a3fb3a1
Merge remote-tracking branch 'refs/remotes/origin/main' into iam-auth
mikealfare Apr 24, 2024
316650b
add region to CI env
mikealfare Apr 24, 2024
1cb8151
Merge branch 'refs/heads/iam-auth' into iam-role-auth
mikealfare Apr 24, 2024
36e0e34
we can only support role credentials by profile
mikealfare Apr 24, 2024
aa1ca4d
Merge branch 'main' into iam-auth
mikealfare Apr 24, 2024
95f8b74
Merge branch 'refs/heads/iam-auth' into iam-role-auth
mikealfare Apr 24, 2024
b3c1c1a
move iam user specific config out of iam and into iam user
mikealfare Apr 24, 2024
72f52de
Merge branch 'refs/heads/iam-auth' into iam-role-auth
mikealfare Apr 24, 2024
26f7912
add type annotations
mikealfare Apr 24, 2024
710acc3
Merge branch 'refs/heads/iam-auth' into iam-role-auth
mikealfare Apr 24, 2024
e2acfc3
move iam defaults out of iam user
mikealfare Apr 24, 2024
92cfff0
Merge branch 'refs/heads/iam-auth' into iam-role-auth
mikealfare Apr 24, 2024
83f9c66
add required params to test profiles
mikealfare Apr 24, 2024
784b31d
Merge branch 'refs/heads/iam-auth' into iam-role-auth
mikealfare Apr 24, 2024
796a9b2
add required params to test profiles
mikealfare Apr 25, 2024
050ab08
simplify test files
mikealfare Apr 25, 2024
ec9e34e
add expected fields back in
mikealfare Apr 25, 2024
8e0f654
split out unit test files
mikealfare Apr 25, 2024
0ce0b81
Merge branch 'refs/heads/iam-auth' into iam-role-auth
mikealfare Apr 25, 2024
4c01ea1
split out unit test files
mikealfare Apr 25, 2024
a70a6ff
Merge branch 'refs/heads/iam-auth' into iam-role-auth
mikealfare Apr 25, 2024
ab8972a
add unit tests for iam role auth method
mikealfare Apr 25, 2024
dcc4f0c
standardize names
mikealfare Apr 25, 2024
88d9ef8
Merge branch 'refs/heads/iam-auth' into iam-role-auth
mikealfare Apr 25, 2024
fbe4154
allow for the default profile
mikealfare Apr 25, 2024
02c8695
add unit tests for iam role access
mikealfare Apr 25, 2024
e874434
changie
mikealfare Apr 25, 2024
93e6026
changie
mikealfare Apr 25, 2024
fe7705a
Merge branch 'main' into iam-auth
colin-rogers-dbt Apr 25, 2024
3fcd320
Merge branch 'main' into iam-auth
mikealfare Apr 26, 2024
740ccf1
Merge branch 'refs/heads/iam-auth' into iam-role-auth
mikealfare Apr 28, 2024
0f89f15
Merge branch 'refs/heads/main' into iam-role-auth
mikealfare May 7, 2024
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
6 changes: 6 additions & 0 deletions .changes/unreleased/Features-20240425-011440.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Features
body: Add support for IAM Role auth
time: 2024-04-25T01:14:40.601575-04:00
custom:
Author: mikealfare,abbywh
Issue: "623"
19 changes: 18 additions & 1 deletion dbt/adapters/redshift/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def get_message(self) -> str:
class RedshiftConnectionMethod(StrEnum):
DATABASE = "database"
IAM = "iam"
IAM_ROLE = "iam_role"


class UserSSLMode(StrEnum):
Expand Down Expand Up @@ -102,9 +103,9 @@ def parse(cls, user_sslmode: UserSSLMode) -> "RedshiftSSLConfig":
@dataclass
class RedshiftCredentials(Credentials):
host: str
user: str
port: Port
method: str = RedshiftConnectionMethod.DATABASE # type: ignore
user: Optional[str] = None
password: Optional[str] = None # type: ignore
cluster_id: Optional[str] = field(
default=None,
Expand Down Expand Up @@ -173,6 +174,8 @@ def get_connect_method(self) -> Callable[[], redshift_connector.Connection]:
kwargs = self._database_kwargs
elif method == RedshiftConnectionMethod.IAM:
kwargs = self._iam_user_kwargs
elif method == RedshiftConnectionMethod.IAM_ROLE:
kwargs = self._iam_role_kwargs
else:
raise FailedToConnectError(f"Invalid 'method' in profile: '{method}'")

Expand Down Expand Up @@ -227,6 +230,20 @@ def _iam_user_kwargs(self) -> Dict[str, Any]:

return kwargs

@property
def _iam_role_kwargs(self) -> Dict[str, Optional[Any]]:
logger.debug("Connecting to redshift with 'iam_role' credentials method")
kwargs = self._iam_kwargs
kwargs.update(
group_federation=True,
db_user=None,
)

if iam_profile := self.credentials.iam_profile:
kwargs.update(profile=iam_profile)

return kwargs

@property
def _iam_kwargs(self) -> Dict[str, Any]:
kwargs = self._base_kwargs
Expand Down
2 changes: 2 additions & 0 deletions dbt/include/redshift/profile_template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ prompts:
hide_input: true
iam:
_fixed_method: iam
iam_role:
_fixed_method: iam_role
dbname:
hint: 'default database that dbt will build objects in'
schema:
Expand Down
7 changes: 6 additions & 1 deletion test.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ REDSHIFT_TEST_USER=
REDSHIFT_TEST_PASS=
REDSHIFT_TEST_REGION=

# IAM User Authentication Method
# IAM Methods
REDSHIFT_TEST_CLUSTER_ID=

# IAM User Authentication Method
REDSHIFT_TEST_IAM_USER_PROFILE=
REDSHIFT_TEST_IAM_USER_ACCESS_KEY_ID=
REDSHIFT_TEST_IAM_USER_SECRET_ACCESS_KEY=

# IAM Role Authentication Method
REDSHIFT_TEST_IAM_ROLE_PROFILE=

# Database users for testing
DBT_TEST_USER_1=dbt_test_user_1
DBT_TEST_USER_2=dbt_test_user_2
Expand Down
16 changes: 16 additions & 0 deletions tests/functional/test_auth_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,19 @@ def dbt_profile_target(self):
"host": "", # host is a required field in dbt-core
"port": 0, # port is a required field in dbt-core
}


class TestIAMRoleAuthProfile(AuthMethod):
@pytest.fixture(scope="class")
def dbt_profile_target(self):
return {
"type": "redshift",
"method": RedshiftConnectionMethod.IAM_ROLE.value,
"cluster_id": os.getenv("REDSHIFT_TEST_CLUSTER_ID"),
"dbname": os.getenv("REDSHIFT_TEST_DBNAME"),
"iam_profile": os.getenv("REDSHIFT_TEST_IAM_ROLE_PROFILE"),
"threads": 1,
"retries": 6,
"host": "", # host is a required field in dbt-core
"port": 0, # port is a required field in dbt-core
}
63 changes: 63 additions & 0 deletions tests/unit/test_auth_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,3 +393,66 @@ def test_profile_invalid_serverless(self):
**DEFAULT_SSL_CONFIG,
)
self.assertTrue("'host' must be provided" in context.exception.msg)


class TestIAMRoleMethod(AuthMethod):

def test_no_cluster_id(self):
self.config.credentials = self.config.credentials.replace(method="iam_role")
with self.assertRaises(FailedToConnectError) as context:
connect_method_factory = RedshiftConnectMethodFactory(self.config.credentials)
connect_method_factory.get_connect_method()

self.assertTrue("'cluster_id' must be provided" in context.exception.msg)

@mock.patch("redshift_connector.connect", MagicMock())
def test_default(self):
self.config.credentials = self.config.credentials.replace(
method="iam_role",
cluster_id="my_redshift",
)
connection = self.adapter.acquire_connection("dummy")
connection.handle
redshift_connector.connect.assert_called_once_with(
iam=True,
host="thishostshouldnotexist.test.us-east-1",
database="redshift",
cluster_identifier="my_redshift",
db_user=None,
password="",
user="",
region=None,
timeout=None,
auto_create=False,
db_groups=[],
port=5439,
group_federation=True,
**DEFAULT_SSL_CONFIG,
)

@mock.patch("redshift_connector.connect", MagicMock())
def test_profile(self):
self.config.credentials = self.config.credentials.replace(
method="iam_role",
cluster_id="my_redshift",
iam_profile="test",
)
connection = self.adapter.acquire_connection("dummy")
connection.handle
redshift_connector.connect.assert_called_once_with(
iam=True,
host="thishostshouldnotexist.test.us-east-1",
database="redshift",
cluster_identifier="my_redshift",
db_user=None,
password="",
user="",
region=None,
timeout=None,
auto_create=False,
db_groups=[],
profile="test",
port=5439,
group_federation=True,
**DEFAULT_SSL_CONFIG,
)
Loading