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

Cross Account resource import and source account tracking #85

Closed
2 tasks
workeitel opened this issue Dec 2, 2019 · 8 comments
Closed
2 tasks

Cross Account resource import and source account tracking #85

workeitel opened this issue Dec 2, 2019 · 8 comments
Assignees

Comments

@workeitel
Copy link

I propose adding a source AWS AccountId property to all Constucts to keep track of the account the resource was defined in.

With the import feature it allows me to pull in "stubs" of resource from other accounts and use it for cross-account operations.

Right now some resources use ARNs which keeps implicilty track of the source account and allow usage of cross account ARNs in for example policies. But not all resources use ARNs. In addition the account Id is not usable independently of the ARN.

Use Case

I thought about use cases like having a APIGW in one account and a Lambda in another account. CDK has already a feature for importing resources. I could import a lambda function by ARN and use it in the code to wire up with APIGW or generate metrics:

Account A – define the Lambda and import APIGW

const fun = lambda.Function( …);
const apigw = apigateway.fromRestApiId(…); // import from account B
apigw.addLambda(fun); // yeah, it’s not exactly as it works today but you get the idea. It would setup the necessary permissions to allow APIGW from account B to call the lambda

Account B – define the APIGW and a cross account tdashboard

const fun = lambda.Function.fromArn("arn:aws:.."); // import from account A by using the ARN
 
dashboard.addWidgets(new GraphWidget({   // build cross account dashboard by using source account Id
  left: [fun.metricErrors()]
});
 
new apigateway.LambdaRestApi(this, 'myapi', {
  handler: fun // actually that case is most likely already working since the ARN is just forwarded
});

That is already working as long as everything is in the same account. But since right now the fromArn is not persisting the AccountId it’s not possible to use the account Id for something like cross account dashboards.

Proposed Solution

I’m wondering if there is the possibility to keep track of AccountId for each construct. Per default it would be always the current account but in case an ARN is used or the AccountId is overridden the other account is used. That would allow for using the AccountId cross account or deny cross account usage in case it’s not supported (like for cross account metrics which is does not work today). Right now that only implicitly works for everything which uses with ARNs since the ARN is including the AccountId.

Something like that should work:

const fun = lambda.Function.fromArn("arn:aws:..");
fun.accountId;

or

const apigw = apigateway.fromRestApiId(“xsthhtkn12”, accountId);
apigw.accountId;

Other

Right now only a few resources support cross account (S3, SNS, Lambda, APIGW, Metrics, Dashboards, SSM Documents, ALB, KMS, SQS, VPCe, maybe more?) but I assume the usage of cross account resources will increase rapidly soon. I was wondering if someone as similar thoughts about making cross account usage easier.

related:


This is a 🚀 Feature Request

@skinny85
Copy link
Contributor

skinny85 commented Dec 2, 2019

I was thinking we need this too. Probably a region property as well, not only account.

@hleb-albau
Copy link

Are there any ways to implement cross region dashboards for ALB's right now?

@workeitel
Copy link
Author

slightly related to aws/aws-cdk@212687c

@eladb eladb transferred this issue from aws/aws-cdk Jan 23, 2020
@eladb
Copy link
Contributor

eladb commented Jan 23, 2020

This is a very interesting idea. I am transferring this to the RFC repo. Please follow the RFC Repo README in order to submit this as an RFC.

@eladb eladb removed their assignment Jan 23, 2020
@skinny85 skinny85 self-assigned this Jan 23, 2020
@eladb
Copy link
Contributor

eladb commented Jun 23, 2020

@skinny85 is still implemented? Can we close this?

@skinny85
Copy link
Contributor

Not yet. It's still in PR: aws/aws-cdk#8280

@workeitel
Copy link
Author

aws/aws-cdk#8280 got merged :) this is so awesome! I assume next step would be to go over all from..Arn methods, parse the ARN and attach the region/account to the resource?

I gave lambda.Function a try and it's surprisingly difficult because the current from method works on Token as well:

diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts
index 04150a2d8..3c1a729be 100644
--- a/packages/@aws-cdk/aws-lambda/lib/function.ts
+++ b/packages/@aws-cdk/aws-lambda/lib/function.ts
@@ -4,7 +4,7 @@ import * as ec2 from '@aws-cdk/aws-ec2';
 import * as iam from '@aws-cdk/aws-iam';
 import * as logs from '@aws-cdk/aws-logs';
 import * as sqs from '@aws-cdk/aws-sqs';
-import { CfnResource, Construct, Duration, Fn, Lazy, Stack } from '@aws-cdk/core';
+import { CfnResource, Construct, Duration, Lazy, Stack, Arn } from '@aws-cdk/core';
 import { Code, CodeConfig } from './code';
 import { EventInvokeConfigOptions } from './event-invoke-config';
 import { IEventSource } from './event-source';
@@ -371,13 +371,13 @@ export class Function extends FunctionBase {
    * @param attrs the attributes of the function to import
    */
   public static fromFunctionAttributes(scope: Construct, id: string, attrs: FunctionAttributes): IFunction {
-    const functionArn = attrs.functionArn;
-    const functionName = extractNameFromArn(attrs.functionArn);
+    const functionArn = Arn.parse(attrs.functionArn, ':');
+    const functionName = functionArn.resourceName!.split(':')[0]; // split optional version part
     const role = attrs.role;
 
     class Import extends FunctionBase {
       public readonly functionName = functionName;
-      public readonly functionArn = functionArn;
+      public readonly functionArn = attrs.functionArn;
       public readonly grantPrincipal: iam.IPrincipal;
       public readonly role = role;
       public readonly permissionsNode = this.node;
@@ -385,7 +385,7 @@ export class Function extends FunctionBase {
       protected readonly canCreatePermissions = false;
 
       constructor(s: Construct, i: string) {
-        super(s, i);
+        super(s, i, { account: functionArn.account, region: functionArn.region });
 
         this.grantPrincipal = role || new iam.UnknownPrincipal({ resource: this });
 
@@ -946,23 +946,6 @@ interface EnvironmentConfig extends EnvironmentOptions {
   readonly value: string;
 }
 
-/**
- * Given an opaque (token) ARN, returns a CloudFormation expression that extracts the function
- * name from the ARN.
- *
- * Function ARNs look like this:
- *
- *   arn:aws:lambda:region:account-id:function:function-name
- *
- * ..which means that in order to extract the `function-name` component from the ARN, we can
- * split the ARN using ":" and select the component in index 6.
- *
- * @returns `FnSelect(6, FnSplit(':', arn))`
- */
-function extractNameFromArn(arn: string) {
-  return Fn.select(6, Fn.split(':', arn));
-}
-
 export function verifyCodeConfig(code: CodeConfig, runtime: Runtime) {
   // mutually exclusive
   if ((!code.inlineCode && !code.s3Location) || (code.inlineCode && code.s3Location)) {

Do you know if the deploy-time ARN parsing is a requirement for import methods?

@nija-at
Copy link
Contributor

nija-at commented Nov 11, 2020

completed here - aws/aws-cdk#8280

@nija-at nija-at closed this as completed Nov 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants