Skip to content

Commit

Permalink
Resource binding customize permissions (#3687)
Browse files Browse the repository at this point in the history
* Allow cusomizing binding permissions

* Rename  function binding to binding

* Docs

* Fix docs

* Fix docs
  • Loading branch information
fwang committed Feb 29, 2024
1 parent e219de7 commit ea060f1
Show file tree
Hide file tree
Showing 35 changed files with 283 additions and 256 deletions.
2 changes: 1 addition & 1 deletion packages/sst/src/cli/commands/bind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const bind = (program: Program) =>
import("../../constructs/StaticSite.js"),
import("../../constructs/deprecated/NextjsSite.js"),
import("../../constructs/Config.js"),
import("../../constructs/util/functionBinding.js"),
import("../../constructs/util/binding.js"),
]);

try {
Expand Down
10 changes: 5 additions & 5 deletions packages/sst/src/constructs/Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import {
FunctionInlineDefinition,
FunctionDefinition,
} from "./Function.js";
import { FunctionBindingProps } from "./util/functionBinding.js";
import { BindingResource, BindingProps } from "./util/binding.js";
import { Duration, toCdkDuration } from "./util/duration.js";
import { Permissions } from "./util/permission.js";
import * as apigV2Cors from "./util/apiGatewayV2Cors.js";
Expand Down Expand Up @@ -762,7 +762,7 @@ export class Api<
| { type: "nlb"; nlb: INetworkListener };
};
private authorizersData: Record<string, IHttpRouteAuthorizer>;
private bindingForAllRoutes: SSTConstruct[] = [];
private bindingForAllRoutes: BindingResource[] = [];
private permissionsAttachedForAllRoutes: Permissions[] = [];

constructor(scope: Construct, id: string, props?: ApiProps<Authorizers>) {
Expand Down Expand Up @@ -879,7 +879,7 @@ export class Api<
* api.bind([STRIPE_KEY, bucket]);
* ```
*/
public bind(constructs: SSTConstruct[]) {
public bind(constructs: BindingResource[]) {
for (const route of Object.values(this.routesData)) {
if (route.type === "function" || route.type === "graphql") {
route.function.bind(constructs);
Expand All @@ -903,7 +903,7 @@ export class Api<
* ```
*
*/
public bindToRoute(routeKey: string, constructs: SSTConstruct[]): void {
public bindToRoute(routeKey: string, constructs: BindingResource[]): void {
const fn = this.getFunction(routeKey);
if (!fn) {
throw new Error(
Expand Down Expand Up @@ -995,7 +995,7 @@ export class Api<
}

/** @internal */
public getFunctionBinding(): FunctionBindingProps {
public getBindings(): BindingProps {
return {
clientPackage: "api",
variables: {
Expand Down
10 changes: 5 additions & 5 deletions packages/sst/src/constructs/ApiGatewayV1Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import * as apigV1AccessLog from "./util/apiGatewayV1AccessLog.js";
import { App } from "./App.js";
import { Stack } from "./Stack.js";
import { Bucket } from "./Bucket.js";
import { FunctionBindingProps } from "./util/functionBinding.js";
import { BindingResource, BindingProps } from "./util/binding.js";
import { Duration, toCdkDuration } from "./util/duration.js";
import { getFunctionRef, SSTConstruct, isCDKConstruct } from "./Construct.js";
import { DnsValidatedCertificate } from "./cdk/dns-validated-certificate.js";
Expand Down Expand Up @@ -580,7 +580,7 @@ export class ApiGatewayV1Api<
private props: ApiGatewayV1ApiProps<Authorizers>;
private functions: { [key: string]: Fn | lambda.IFunction } = {};
private authorizersData: Record<string, apig.IAuthorizer> = {};
private bindingForAllRoutes: SSTConstruct[] = [];
private bindingForAllRoutes: BindingResource[] = [];
private permissionsAttachedForAllRoutes: Permissions[] = [];

constructor(
Expand Down Expand Up @@ -697,7 +697,7 @@ export class ApiGatewayV1Api<
* api.bind([STRIPE_KEY, bucket]);
* ```
*/
public bind(constructs: SSTConstruct[]) {
public bind(constructs: BindingResource[]) {
Object.values(this.functions).forEach((fn) => {
if (fn instanceof Fn) {
fn.bind(constructs);
Expand All @@ -721,7 +721,7 @@ export class ApiGatewayV1Api<
* ```
*
*/
public bindToRoute(routeKey: string, constructs: SSTConstruct[]): void {
public bindToRoute(routeKey: string, constructs: BindingResource[]): void {
const fn = this.getFunction(routeKey);
if (!fn) {
throw new Error(
Expand Down Expand Up @@ -797,7 +797,7 @@ export class ApiGatewayV1Api<
}

/** @internal */
public getFunctionBinding(): FunctionBindingProps {
public getBindings(): BindingProps {
return {
clientPackage: "api",
variables: {
Expand Down
28 changes: 12 additions & 16 deletions packages/sst/src/constructs/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import {
} from "./Construct.js";
import { FunctionProps, useFunctions } from "./Function.js";
import { Permissions } from "./util/permission.js";
import { bindParameters, bindType } from "./util/functionBinding.js";
import {
BindingResource,
getBindingParameters,
getBindingType,
} from "./util/binding.js";
import { StackProps } from "./Stack.js";
import { FunctionalStack, stack } from "./FunctionalStack.js";
import { Auth } from "./Auth.js";
Expand Down Expand Up @@ -236,7 +240,7 @@ export class App extends CDKApp {
* app.addDefaultFunctionBinding([STRIPE_KEY, bucket]);
* ```
*/
public addDefaultFunctionBinding(bind: SSTConstruct[]) {
public addDefaultFunctionBinding(bind: BindingResource[]) {
this.defaultFunctionProps.push({ bind });
}

Expand Down Expand Up @@ -288,7 +292,7 @@ export class App extends CDKApp {
return;
}

const binding = bindType(c);
const binding = getBindingType(c);
if (!binding) {
return;
}
Expand Down Expand Up @@ -435,14 +439,10 @@ export class App extends CDKApp {
private createBindingSsmParameters() {
class CreateSsmParameters implements IAspect {
public visit(c: IConstruct): void {
if (!isSSTConstruct(c)) {
return;
}
if ("_doNotAllowOthersToBind" in c && c._doNotAllowOthersToBind) {
return;
}
if (!isSSTConstruct(c)) return;
if ("_doNotAllowOthersToBind" in c && c._doNotAllowOthersToBind) return;

bindParameters(c);
getBindingParameters(c);
}
}

Expand Down Expand Up @@ -562,12 +562,8 @@ export class App extends CDKApp {

class EnsureUniqueConstructIds implements IAspect {
public visit(c: IConstruct): void {
if (!isSSTConstruct(c)) {
return;
}
if ("_doNotAllowOthersToBind" in c && c._doNotAllowOthersToBind) {
return;
}
if (!isSSTConstruct(c)) return;
if ("_doNotAllowOthersToBind" in c && c._doNotAllowOthersToBind) return;

const className = c.constructor.name;
const id = c.id;
Expand Down
12 changes: 6 additions & 6 deletions packages/sst/src/constructs/AppSyncApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
FunctionInlineDefinition,
FunctionDefinition,
} from "./Function.js";
import { FunctionBindingProps } from "./util/functionBinding.js";
import { BindingResource, BindingProps } from "./util/binding.js";
import { Permissions } from "./util/permission.js";
import { useProject } from "../project.js";
import { Table as CDKTable } from "aws-cdk-lib/aws-dynamodb";
Expand Down Expand Up @@ -494,7 +494,7 @@ export class AppSyncApi extends Construct implements SSTConstruct {
} = {};
private readonly dsKeysByResKey: { [key: string]: string } = {};
private readonly resolversByResKey: { [key: string]: Resolver } = {};
private readonly bindingForAllFunctions: SSTConstruct[] = [];
private readonly bindingForAllFunctions: BindingResource[] = [];
private readonly permissionsAttachedForAllFunctions: Permissions[] = [];

constructor(scope: Construct, id: string, props: AppSyncApiProps) {
Expand Down Expand Up @@ -667,7 +667,7 @@ export class AppSyncApi extends Construct implements SSTConstruct {
* api.bind([STRIPE_KEY, bucket]);
* ```
*/
public bind(constructs: SSTConstruct[]) {
public bind(constructs: BindingResource[]) {
Object.values(this.functionsByDsKey).forEach((fn) => fn.bind(constructs));
this.bindingForAllFunctions.push(...constructs);
}
Expand All @@ -681,7 +681,7 @@ export class AppSyncApi extends Construct implements SSTConstruct {
* ```
*
*/
public bindToDataSource(key: string, constructs: SSTConstruct[]): void {
public bindToDataSource(key: string, constructs: BindingResource[]): void {
const fn = this.getFunction(key);
if (!fn) {
throw new Error(
Expand Down Expand Up @@ -746,7 +746,7 @@ export class AppSyncApi extends Construct implements SSTConstruct {
}

/** @internal */
public getFunctionBinding() {
public getBindings() {
// Do not bind imported AppSync APIs b/c we don't know the API URL
if (!this.url) {
return;
Expand All @@ -761,7 +761,7 @@ export class AppSyncApi extends Construct implements SSTConstruct {
},
},
permissions: {},
} as FunctionBindingProps;
} as BindingProps;
}

private createGraphApi() {
Expand Down
8 changes: 4 additions & 4 deletions packages/sst/src/constructs/Auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import { SSTConstruct } from "./Construct.js";
import { App } from "./App.js";
import { Stack } from "./Stack.js";
import {
FunctionBindingProps,
BindingProps,
getEnvironmentKey,
getParameterPath,
placeholderSecretValue,
} from "./util/functionBinding.js";
} from "./util/binding.js";
import { CustomResource } from "aws-cdk-lib/core";

const PUBLIC_KEY_PROP = "publicKey";
Expand Down Expand Up @@ -146,7 +146,7 @@ export class Auth extends Construct implements SSTConstruct {
}

/** @internal */
public getFunctionBinding(): FunctionBindingProps {
public getBindings(): BindingProps {
const app = this.node.root as App;
return {
clientPackage: "auth",
Expand Down Expand Up @@ -213,7 +213,7 @@ export class Auth extends Construct implements SSTConstruct {
});

// Auth construct has two types of Function bindinds:
// - Api routes: bindings defined in `getFunctionBinding()`
// - Api routes: bindings defined in `getBindings()`
// ie. calling `bind([auth])` will grant functions access to the public key
// - Auth authenticator: binds manually. Need to grant access to the prefix and private key
const fn = props.api.getFunction(path)!;
Expand Down
10 changes: 5 additions & 5 deletions packages/sst/src/constructs/Bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
FunctionInlineDefinition,
FunctionDefinition,
} from "./Function.js";
import { FunctionBindingProps } from "./util/functionBinding.js";
import { BindingResource, BindingProps } from "./util/binding.js";
import { Permissions } from "./util/permission.js";
import { Duration, toCdkDuration } from "./util/duration.js";
import {
Expand Down Expand Up @@ -300,7 +300,7 @@ export class Bucket extends Construct implements SSTConstruct {
bucket: IBucket;
};
readonly notifications: Record<string, Fn | Queue | Topic> = {};
readonly bindingForAllNotifications: SSTConstruct[] = [];
readonly bindingForAllNotifications: BindingResource[] = [];
readonly permissionsAttachedForAllNotifications: Permissions[] = [];
readonly props: BucketProps;

Expand Down Expand Up @@ -384,7 +384,7 @@ export class Bucket extends Construct implements SSTConstruct {
* bucket.bind([STRIPE_KEY, bucket]);
* ```
*/
public bind(constructs: SSTConstruct[]) {
public bind(constructs: BindingResource[]) {
this.notificationFunctions.forEach((notification) =>
notification.bind(constructs)
);
Expand All @@ -407,7 +407,7 @@ export class Bucket extends Construct implements SSTConstruct {
*/
public bindToNotification(
notificationName: string,
constructs: SSTConstruct[]
constructs: BindingResource[]
): void {
const notification = this.notifications[notificationName];
if (!(notification instanceof Fn)) {
Expand Down Expand Up @@ -477,7 +477,7 @@ export class Bucket extends Construct implements SSTConstruct {
}

/** @internal */
public getFunctionBinding(): FunctionBindingProps {
public getBindings(): BindingProps {
return {
clientPackage: "bucket",
variables: {
Expand Down
7 changes: 4 additions & 3 deletions packages/sst/src/constructs/Cognito.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
PolicyStatement,
Role,
} from "aws-cdk-lib/aws-iam";
import { BindingResource } from "./util/binding.js";

const CognitoUserPoolTriggerOperationMapping = {
createAuthChallenge: UserPoolOperation.CREATE_AUTH_CHALLENGE,
Expand Down Expand Up @@ -301,13 +302,13 @@ export class Cognito extends Construct implements SSTConstruct {
return this.attachPermissionsForUsers(this.cdk.unauthRole, arg1, arg2);
}

public bindForTriggers(constructs: SSTConstruct[]): void {
public bindForTriggers(constructs: BindingResource[]): void {
Object.values(this.functions).forEach((fn) => fn.bind(constructs));
}

public bindForTrigger(
triggerKey: keyof CognitoUserPoolTriggers,
constructs: SSTConstruct[]
constructs: BindingResource[]
): void {
const fn = this.getFunction(triggerKey);
if (!fn) {
Expand Down Expand Up @@ -360,7 +361,7 @@ export class Cognito extends Construct implements SSTConstruct {
}

/** @internal */
public getFunctionBinding() {
public getBindings() {
return undefined;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/sst/src/constructs/Construct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Construct } from "constructs";
import { Stack as CDKStack } from "aws-cdk-lib/core";
import { Function as Fn } from "aws-cdk-lib/aws-lambda";
import { Stack } from "./Stack.js";
import { FunctionBindingProps } from "./util/functionBinding.js";
import { BindingProps } from "./util/binding.js";

const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");

Expand All @@ -19,7 +19,7 @@ export interface SSTConstructMetadata<
export interface SSTConstruct extends Construct {
id: string;
getConstructMetadata(): SSTConstructMetadata;
getFunctionBinding(): FunctionBindingProps | undefined;
getBindings(): BindingProps | undefined;
}

export function getFunctionRef(fn?: any) {
Expand Down
6 changes: 3 additions & 3 deletions packages/sst/src/constructs/Cron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
FunctionInlineDefinition,
FunctionDefinition,
} from "./Function.js";
import { FunctionBindingProps } from "./util/functionBinding.js";
import { BindingResource } from "./util/binding.js";
import { Permissions } from "./util/permission.js";

export interface CronJobProps {
Expand Down Expand Up @@ -162,7 +162,7 @@ export class Cron extends Construct implements SSTConstruct {
* ```
*
*/
public bind(constructs: SSTConstruct[]) {
public bind(constructs: BindingResource[]) {
this.jobFunction.bind(constructs);
}

Expand Down Expand Up @@ -193,7 +193,7 @@ export class Cron extends Construct implements SSTConstruct {
}

/** @internal */
public getFunctionBinding() {
public getBindings() {
return undefined;
}

Expand Down

0 comments on commit ea060f1

Please sign in to comment.