Skip to content

Commit

Permalink
feat(resource-binding): Create a file with a security group ID when i…
Browse files Browse the repository at this point in the history
…t is defined as AccessSecurityGroupId in the resource manifest
  • Loading branch information
Florian Aymard committed Feb 18, 2025
1 parent fd3d3e2 commit b32ba9e
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 7 deletions.
12 changes: 12 additions & 0 deletions backstage-plugins/plugins/aws-apps-backend/src/api/aws-platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,12 @@ export class AwsAppsPlatformApi {
content: resourceBindContent,
});

input.securityGroupIds.forEach((securityGroupId) => actions.push({
action: 'create',
file_path: `.iac/security-groups/${input.envName}/${input.providerName}/${securityGroupId}`,
content: ''
}))

const change:ICommitChange = {
commitMessage: `Bind Resource`,
branch: 'main',
Expand Down Expand Up @@ -352,6 +358,12 @@ export class AwsAppsPlatformApi {
content: resourceBindContent,
});

input.securityGroupIds.forEach((securityGroupId) => actions.push({
action: 'delete',
file_path: `.iac/security-groups/${input.envName}/${input.providerName}/${securityGroupId}`,
content: ''
}))

const change:ICommitChange = {
commitMessage: `UnBind Resource`,
branch: 'main',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,13 +309,15 @@ export async function createRouter(options: RouterOptions): Promise<express.Rout
const resourceName = req.body.resourceName?.toString();
const resourceEntityRef = req.body.resourceEntityRef?.toString();
const policies = req.body.policies;
const securityGroupIds = req.body.securityGroupIds || [];
const params: BindResourceParams = {
envName,
appName,
providerName,
resourceName,
resourceEntityRef,
policies
policies,
securityGroupIds
};
// console.log(params)
const results = await apiPlatformClient.bindResource(repoInfo,params, secretName);
Expand All @@ -337,12 +339,14 @@ export async function createRouter(options: RouterOptions): Promise<express.Rout
const resourceName = req.body.resourceName?.toString();
const resourceEntityRef = req.body.resourceEntityRef?.toString();
const policies = req.body.policies;
const securityGroupIds = req.body.securityGroupIds || [];
const params: BindResourceParams = {
envName,
appName,
providerName,
resourceName,
resourceEntityRef,
securityGroupIds,
policies
};
// console.log(params)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface ResourceBinding {
provider: string;
resourceArn: string;
associatedResources?: AssociatedResources[]
securityGroupIds?: string[]
entityRef?:string;
}

Expand All @@ -55,6 +56,7 @@ export interface BindResourceParams {
resourceName:string;
resourceEntityRef:string;
policies: ResourcePolicy[];
securityGroupIds: string[];
appName: string;
}

Expand Down
6 changes: 4 additions & 2 deletions backstage-plugins/plugins/aws-apps/src/api/OPAApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ export class OPAApiClient implements OPAApi {
envName: params.envName,
policies: params.policies,
resourceName: params.resourceName,
resourceEntityRef: params.resourceEntityRef
resourceEntityRef: params.resourceEntityRef,
securityGroupIds: params.securityGroupIds
}

const bindResponse = this.fetch<any>('/platform/bind-resource', HTTP.POST, postBody);
Expand Down Expand Up @@ -259,7 +260,8 @@ export class OPAApiClient implements OPAApi {
envName: params.envName,
policies: params.policies,
resourceName: params.resourceName,
resourceEntityRef: params.resourceEntityRef
resourceEntityRef: params.resourceEntityRef,
securityGroupIds: params.securityGroupIds
}

const unBindResponse = this.fetch<any>('/platform/unbind-resource', HTTP.POST, postBody);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const ResourceBindingCard = ({
resourceArn: providerAppData['Arn'],
id: providerAppData['Arn'],
entityRef: "resource:default/" + et!.metadata.name,
securityGroupIds: providerAppData['AccessSecurityGroupId'] ? [providerAppData['AccessSecurityGroupId']] : [],
associatedResources: [associatedRDSResources]
})
}
Expand Down Expand Up @@ -173,6 +174,7 @@ const ResourceBindingCard = ({
appName: entity.metadata.name,
resourceName: item.resourceName,
resourceEntityRef: item.id,
securityGroupIds: item.securityGroupIds || [],
policies
};

Expand Down Expand Up @@ -214,6 +216,7 @@ const ResourceBindingCard = ({
appName: entity.metadata.name,
resourceName: item.resourceName,
resourceEntityRef: item.entityRef!,
securityGroupIds: item.securityGroupIds || [],
policies
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export const ResourceSelectorDialog = ({
provider: p,
resourceArn: providerAppData['Arn'],
id,
securityGroupIds: providerAppData['AccessSecurityGroupId'] ? [providerAppData['AccessSecurityGroupId']] : [],
associatedResources: [associatedRDSResources]
})
}
Expand Down
25 changes: 21 additions & 4 deletions backstage-reference/common/aws_ecs/src/cdk-ecs-module-stack.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { validate } from "@aws-sdk/util-arn-parser";
import { CfnOutput, RemovalPolicy, Stack, StackProps, Tags } from "aws-cdk-lib";
import { CfnOutput, Fn, RemovalPolicy, Stack, StackProps, Tags } from "aws-cdk-lib";
import * as ec2 from "aws-cdk-lib/aws-ec2";
import * as efs from "aws-cdk-lib/aws-efs";
import * as ecr from "aws-cdk-lib/aws-ecr";
Expand All @@ -11,8 +11,9 @@ import * as rg from "aws-cdk-lib/aws-resourcegroups";
import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager";
import * as ssm from "aws-cdk-lib/aws-ssm";
import { Construct } from "constructs";
import * as fs from 'fs'
import * as fs from 'fs';
import { PolicyStatement } from "aws-cdk-lib/aws-iam";
import {ISecurityGroup, Peer, Port, SecurityGroup} from "aws-cdk-lib/aws-ec2";

interface PermissionList {
[key: string]: string[] // adjusting require this in order to some json data type
Expand All @@ -33,6 +34,13 @@ export function DeclareJSONStatements(readPermissionsPath:string): PermissionLis
return list
}

export function DeclareSecurityGroupIds(readSecurityGroupIdsPath: string): string[] {
if (fs.existsSync(readSecurityGroupIdsPath)) {
return fs.readdirSync(readSecurityGroupIdsPath);
}
else return [];
}

// Environment variables that can be passed in and used in this stack
// The env var names must match the values passed in from scaffolder action(s) building this stack
const StackVarNames = {
Expand Down Expand Up @@ -76,7 +84,7 @@ export class EcsResourcesStack extends Stack {

// Search for the particular env/provider permissions to apply
const readPermissionsPath = `./permissions/${envName}/${envProviderName}/`

const readSecurityGroupIdsPath = `./security-groups/${envName}/${envProviderName}/`
// Add any tags passed as part of AWS_RESOURCE_TAGS input parameters
const resourceTagsEnvVar = process.env.AWS_RESOURCE_TAGS;
if (resourceTagsEnvVar) {
Expand Down Expand Up @@ -173,16 +181,25 @@ export class EcsResourcesStack extends Stack {
}),
portMappings: [{containerPort: +appPort}],
});


const applicationSecurityGroup = new ec2.SecurityGroup(this, `${appShortName}-securityGroup`, {
vpc
})

const securityGroups : ISecurityGroup[] = DeclareSecurityGroupIds(readSecurityGroupIdsPath).map((securityGroupId) => SecurityGroup.fromLookupById(this, securityGroupId, securityGroupId));

// Create an ECS service with an application load balancer in front
const loadBalancedEcsService = new ALBService(this, `${appShortName}-ecspattern`, {
cluster,
serviceName: `${appShortName}-${envProviderName}`,
taskDefinition,
securityGroups: [applicationSecurityGroup, ...securityGroups]
// enableExecuteCommand: true, // Enable this for debugging and executing commands in the container
}
);

applicationSecurityGroup.addIngressRule(Peer.securityGroupId(Fn.select(0, loadBalancedEcsService.loadBalancer.loadBalancerSecurityGroups)), Port.tcp(+appPort));
applicationSecurityGroup.addEgressRule(Peer.anyIpv4(), Port.allTraffic());
// L3 construct above does not allow desiredCount to be 0, so drop down to L2 constructs to set value
const cfnEcsService = loadBalancedEcsService.service.node.defaultChild as ecs.CfnService;
cfnEcsService.desiredCount = 0;
Expand Down

0 comments on commit b32ba9e

Please sign in to comment.