From fb867eeba51f8a167fae457c9590545ccbc7ecbd Mon Sep 17 00:00:00 2001 From: Adam Corriveau Date: Mon, 10 Mar 2025 14:27:16 -0400 Subject: [PATCH 1/4] small modiffication --- Makefile | 3 +++ src/context/account.py | 58 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 58a7516..14d22ed 100644 --- a/Makefile +++ b/Makefile @@ -28,5 +28,8 @@ lint: up: @$(ACTIVATE) AWS_PROFILE=$(PROFILE) pulumi up --stack juno +down: + @$(ACTIVATE) AWS_PROFILE=$(PROFILE) pulumi destroy --stack juno + refresh: @$(ACTIVATE) PULUMI_K8S_DELETE_UNREACHABLE=true AWS_PROFILE=$(PROFILE) pulumi refresh --stack juno diff --git a/src/context/account.py b/src/context/account.py index e4dcd76..2342fbf 100644 --- a/src/context/account.py +++ b/src/context/account.py @@ -3,8 +3,8 @@ """ # 3rd -from pulumi_aws.iam import User, UserPolicyAttachment, AccessKey -from pulumi import get_stack, InvokeOptions, ResourceOptions +import boto3 +from pulumi import get_stack, InvokeOptions import pulumi_aws as aws # local @@ -13,7 +13,26 @@ from .session import get_session # Juno org -organization = aws.organizations.get_organization() + +# Get The Account ID for the organization +def get_current_account_id(): + org = aws.organizations.get_organization() + return org.master_account_id + +# Get The current account ARN to build the environment +def get_current_user_arn(): + client = boto3.client('sts') + user_arn = client.get_caller_identity().get('Arn') + return user_arn + +# Verify the current account can create the resources +def has_administrator_access(user_name): + iam_client = boto3.client('iam') + attached_policies = iam_client.list_attached_user_policies(UserName=user_name) + for policy in attached_policies['AttachedPolicies']: + if policy['PolicyName'] == 'AdministratorAccess': + return True + return False # account hooks # these are functions that will be called when the account is initialized @@ -34,13 +53,40 @@ def set_root_account(account): def __init__(self, account: str): # instance variables self.account = "root" if account == JunoAccount.ROOT_ACCOUNT else account - self.account_object = [acct for acct in organization.accounts if acct.name == account][0] - self.account_id = self.account_object.id + # self.account_object = [acct for acct in organization.accounts if acct.name == account][0] + self.account_id = get_current_account_id() + if has_administrator_access(self.account): + current_user_arn = get_current_user_arn() + role = aws.iam.Role( + '{self.account}-OrganizationAccountAccessRole', + assume_role_policy=f""" + {{ + "Version": "2012-10-17", + "Statement": [ + {{ + "Effect": "Allow", + "Principal": {{ + "AWS": "{current_user_arn}" + }}, + "Action": "sts:AssumeRole" + }} + ] + }} + """ + ) + admin_policy_attachment = aws.iam.RolePolicyAttachment( + 'adminPolicyAttachment', + role=role.name, + policy_arn='arn:aws:iam::aws:policy/AdministratorAccess' + ) + else: + raise ValueError("Please Create user with the default aws roles an permission for the deployment ") + args = dict(allowed_account_ids=[self.account_id]) if self.account != "root": args["assume_role"] = aws.ProviderAssumeRoleArgs( - role_arn=f"arn:aws:iam::{self.account_id}:role/OrganizationAccountAccessRole", + role_arn=f"arn:aws:iam::{self.account_id}:role/{self.account}-OrganizationAccountAccessRole", session_name=get_session(), ) From 7069fe673c0c84ed63909f9e3f40bb9369df189c Mon Sep 17 00:00:00 2001 From: Adam Corriveau Date: Mon, 10 Mar 2025 14:37:06 -0400 Subject: [PATCH 2/4] test the new part --- src/context/region.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/context/region.py b/src/context/region.py index e398a83..3c39342 100644 --- a/src/context/region.py +++ b/src/context/region.py @@ -3,6 +3,7 @@ """ # 3rd +import boto3 from pulumi import ResourceOptions, get_stack import pulumi_aws as aws @@ -20,6 +21,28 @@ REGION_HOOKS = {} PROVIDERS = {} +# Get The Account ID for the organization +def get_current_account_id(): + org = aws.organizations.get_organization() + return org.master_account_id + +# Get The current account ARN to build the environment +def get_current_user_arn(): + client = boto3.client('sts') + user_arn = client.get_caller_identity().get('Arn') + return user_arn + +# Verify the current account can create the resources +def has_administrator_access(user_name): + iam_client = boto3.client('iam') + attached_policies = iam_client.list_attached_user_policies(UserName=user_name) + for policy in attached_policies['AttachedPolicies']: + if policy['PolicyName'] == 'AdministratorAccess': + return True + return False + + + class JunoRegion: def __init__(self, region: str, ecr_master: bool = False, ecr_sync: bool = False): @@ -31,8 +54,8 @@ def __init__(self, region: str, ecr_master: bool = False, ecr_sync: bool = False self.region = region self.account = account.account self.context_only = False - self.account_id = account.account_id - self.role_arn = f"arn:aws:iam::{self.account_id}:role/OrganizationAccountAccessRole" + self.account_id = get_current_account_id() + self.role_arn = f"arn:aws:iam::{self.account_id}:role/{self.account}-OrganizationAccountAccessRole" args = dict(profile=get_profile(), allowed_account_ids=[self.account_id], region=region) if self.account != "root": From e8a9269b433717535f8fa14802a0d2ea0a98dd0c Mon Sep 17 00:00:00 2001 From: Adam Corriveau Date: Thu, 13 Mar 2025 10:46:34 -0400 Subject: [PATCH 3/4] Configuration change --- __main__.py | 48 +++++++++++++++++++++++++++++++++++++-- src/context/account.py | 51 +++++------------------------------------- src/context/region.py | 28 +++-------------------- 3 files changed, 54 insertions(+), 73 deletions(-) diff --git a/__main__.py b/__main__.py index b92ca95..33ed021 100644 --- a/__main__.py +++ b/__main__.py @@ -1,6 +1,8 @@ """ Juno Innovations - EKS Infrastructure for Orion """ +from dotenv import load_dotenv +load_dotenv() # local from src import JunoAccount, JunoRegion, Cluster, set_repositories, set_profile, set_session @@ -39,6 +41,48 @@ ]) + + + +# account in standalone in personal setup +# Steps to create a role with the option to select a trusted entity (current account or remote account): +# +# 1. Navigate to the IAM Console: +# Open the AWS Management Console, go to the IAM (Identity and Access Management) service, +# and select "Roles" from the left-hand navigation pane. Click on the "Create role" button +# to start the role creation process. +# +# 2. Select Trusted Entity: +# Choose the type of trusted entity for the role. You can select "AWS account" to specify +# either the current account or a remote account. If you choose "Another AWS account," you +# will need to enter the Account ID of the remote account. +# +# 3. Define Permissions: +# Attach the necessary permissions policies to the role. These policies define what actions +# the role can perform. Make sure that the define role can create VPC , Nodegroup , EKS , internet gateway Security group and IAM roles with the account +# +# 4. Configure Role Settings: +# Provide a name and description for the role, and review the trust policy. The trust policy +# specifies which entities (accounts) are allowed to assume the role + + + +# Those value are necessary on user account without organization role +# But is usefull for standolone practice of when someone grant an assume role to their account +assume_role_name = "JunoAdmin" + + +# Stand Alone Example For personal account not link to an organization +#with JunoAccount("deployment_account_name" , admin_role=assume_role_name ): # this is the account that will be used to deploy the clusters and also the the role it will assume at creation +# with JunoRegion("us-east-1", ecr_master=True , admin_role=assume_role_name ): # this is the region that the clusters will be deployed to it need the assume role name to follow along an do impersonation +# pass + +# Stand Alone Example with permission to assume another oganization roles +#with JunoAccount("deployment_account_name" , account_id="changemetospecificaccountid" , admin_role=assume_role_name ): # this is the account that will be used to deploy the clusters and also the the role it will assume at creation +# with JunoRegion("us-east-1", ecr_master=True , admin_role=assume_role_name ): # this is the region that the clusters will be deployed to it need the assume role name to follow along an do impersonation +# pass + + # account and regional deployments with JunoAccount("deployment_account_name"): # this is the account that will be used to deploy the clusters with JunoRegion("us-east-1", ecr_master=True): # this is the region that the clusters will be deployed to @@ -50,8 +94,8 @@ # name="service", # instances=["c6a.xlarge", "t3.xlarge"], # capacity_type=cluster.CapacityType.SPOT, - # minimum=1, - # size=1, + # minimum=2, + # size=2, # maximum=5, # labels={ # "juno-innovations.com/service": "true" diff --git a/src/context/account.py b/src/context/account.py index 2342fbf..e8ae442 100644 --- a/src/context/account.py +++ b/src/context/account.py @@ -19,21 +19,6 @@ def get_current_account_id(): org = aws.organizations.get_organization() return org.master_account_id -# Get The current account ARN to build the environment -def get_current_user_arn(): - client = boto3.client('sts') - user_arn = client.get_caller_identity().get('Arn') - return user_arn - -# Verify the current account can create the resources -def has_administrator_access(user_name): - iam_client = boto3.client('iam') - attached_policies = iam_client.list_attached_user_policies(UserName=user_name) - for policy in attached_policies['AttachedPolicies']: - if policy['PolicyName'] == 'AdministratorAccess': - return True - return False - # account hooks # these are functions that will be called when the account is initialized # they are filtered by stack name. So if you want to only run a hook for @@ -50,43 +35,17 @@ class JunoAccount: def set_root_account(account): JunoAccount.ROOT_ACCOUNT = account - def __init__(self, account: str): + def __init__(self, account: str, admin_role: str = "OrganizationAccountAccessRole", account_id: str = None): # instance variables self.account = "root" if account == JunoAccount.ROOT_ACCOUNT else account - # self.account_object = [acct for acct in organization.accounts if acct.name == account][0] - self.account_id = get_current_account_id() - if has_administrator_access(self.account): - current_user_arn = get_current_user_arn() - role = aws.iam.Role( - '{self.account}-OrganizationAccountAccessRole', - assume_role_policy=f""" - {{ - "Version": "2012-10-17", - "Statement": [ - {{ - "Effect": "Allow", - "Principal": {{ - "AWS": "{current_user_arn}" - }}, - "Action": "sts:AssumeRole" - }} - ] - }} - """ - ) - admin_policy_attachment = aws.iam.RolePolicyAttachment( - 'adminPolicyAttachment', - role=role.name, - policy_arn='arn:aws:iam::aws:policy/AdministratorAccess' - ) - else: - raise ValueError("Please Create user with the default aws roles an permission for the deployment ") - + # Get user ID if account not specified + self.account_id = account_id if account_id else get_current_account_id() + args = dict(allowed_account_ids=[self.account_id]) if self.account != "root": args["assume_role"] = aws.ProviderAssumeRoleArgs( - role_arn=f"arn:aws:iam::{self.account_id}:role/{self.account}-OrganizationAccountAccessRole", + role_arn=f"arn:aws:iam::{self.account_id}:role/{admin_role}", session_name=get_session(), ) diff --git a/src/context/region.py b/src/context/region.py index 3c39342..1653916 100644 --- a/src/context/region.py +++ b/src/context/region.py @@ -21,31 +21,9 @@ REGION_HOOKS = {} PROVIDERS = {} -# Get The Account ID for the organization -def get_current_account_id(): - org = aws.organizations.get_organization() - return org.master_account_id - -# Get The current account ARN to build the environment -def get_current_user_arn(): - client = boto3.client('sts') - user_arn = client.get_caller_identity().get('Arn') - return user_arn - -# Verify the current account can create the resources -def has_administrator_access(user_name): - iam_client = boto3.client('iam') - attached_policies = iam_client.list_attached_user_policies(UserName=user_name) - for policy in attached_policies['AttachedPolicies']: - if policy['PolicyName'] == 'AdministratorAccess': - return True - return False - - - class JunoRegion: - def __init__(self, region: str, ecr_master: bool = False, ecr_sync: bool = False): + def __init__(self, region: str, ecr_master: bool = False, ecr_sync: bool = False , admin_role: str = "OrganizationAccountAccessRole"): account = get_account() # instance variables @@ -54,8 +32,8 @@ def __init__(self, region: str, ecr_master: bool = False, ecr_sync: bool = False self.region = region self.account = account.account self.context_only = False - self.account_id = get_current_account_id() - self.role_arn = f"arn:aws:iam::{self.account_id}:role/{self.account}-OrganizationAccountAccessRole" + self.account_id = account.account_id + self.role_arn = f"arn:aws:iam::{self.account_id}:role/{admin_role}" args = dict(profile=get_profile(), allowed_account_ids=[self.account_id], region=region) if self.account != "root": From 359338f019d37c8038a756c34b571abe8b0740c8 Mon Sep 17 00:00:00 2001 From: Adam Corriveau Date: Thu, 13 Mar 2025 10:55:23 -0400 Subject: [PATCH 4/4] Adding the extra package and updated gitignore --- .gitignore | 2 ++ requirements.txt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 53fe4cf..d2eab15 100644 --- a/.gitignore +++ b/.gitignore @@ -155,3 +155,5 @@ Thumbs.db # pycharm .idea .venv + +.env \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index cc0bc18..fdb692e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,3 +19,5 @@ ruff==0.3.5 semver==2.13.0 six==1.16.0 urllib3==2.2.1 +boto3 +python-dotenv \ No newline at end of file