Skip to content

Commit

Permalink
comments and remove explicit block. no in rules means blocked
Browse files Browse the repository at this point in the history
  • Loading branch information
orcutt989 committed Apr 11, 2024
1 parent 42854fe commit 768b1e3
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 42 deletions.
28 changes: 13 additions & 15 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const vpc = new awsx.ec2.Vpc(`${ownerTag}-vpc`, {
});

// Define the role mappings for the EKS cluster
// Opened up to all authenticated accounts for simplicity
// As to not worry about role-based authentication
// although that is best-practice.
const roleMappings: eks.RoleMapping[] = [{
roleArn: "*",
username: "*",
Expand Down Expand Up @@ -52,10 +55,10 @@ const redisService = new k8s.core.v1.Service("redis-service", {
namespace: "default"
},
spec: {
type: "ClusterIP",
type: "ClusterIP", // Only accessible inside the cluster. Redis doesnt need outside access.
ports: [{
port: redisPort,
targetPort: "redis",
targetPort: "redis", // Named port matches named port in deployment
}],
selector: {
app: "redis"
Expand Down Expand Up @@ -93,7 +96,7 @@ const redisDeployment = new k8s.apps.v1.Deployment("redis-deployment", {
name: "redis",
image: "redis",
ports: [{
name: "redis",
name: "redis", // Named port matches named port in service
containerPort: 6379
}],
env: [{
Expand All @@ -103,8 +106,8 @@ const redisDeployment = new k8s.apps.v1.Deployment("redis-deployment", {
name: "REDIS_HOST",
value: "0.0.0.0"
}],
command: ["redis-server"], // Specify the command to run Redis
args: ["--bind", "0.0.0.0"], // Specify the bind address
command: ["redis-server"],
args: ["--bind", "0.0.0.0"],
}],
},
},
Expand Down Expand Up @@ -161,7 +164,7 @@ const webAppService = new k8s.core.v1.Service("webapp-service", {
namespace: "default"
},
spec: {
type: "LoadBalancer",
type: "LoadBalancer", // Accessible via AWS ELB URL on the internet
ports: [{
port: 80,
targetPort: 4567
Expand All @@ -180,7 +183,7 @@ const webAppService = new k8s.core.v1.Service("webapp-service", {
// Create the RDS database instance using the createRDS function
export function createRDS() {

// Cant have uppercase leters in RDS and subnet names.
// Cant have uppercase letters in RDS and subnet names.
const rdsName = `${ownerTag!.toLowerCase()}-rds-instance`.toLowerCase().replace(/[^a-z0-9-]+/g, "");

// Create a subnet group for the RDS instance
Expand All @@ -203,12 +206,7 @@ export function createRDS() {
// And denies from everywhere else
const dbSecurityGroup = new aws.ec2.SecurityGroup(`${ownerTag}-db-security-group`, {
vpcId: vpc.vpcId,
ingress: [ {
protocol: "-1", // -1 means all protocols
fromPort: 0,
toPort: 0,
cidrBlocks: ["0.0.0.0/0"], // Deny from all sources
},{
ingress: [{ //Absence of any other rules means all inbound traffic is denied
protocol: "tcp",
fromPort: 3306,
toPort: 3306,
Expand Down Expand Up @@ -237,10 +235,10 @@ export function createRDS() {
engine: "mysql",
engineVersion: "8.0",
instanceClass: "db.t3.micro",
dbName: `${ownerTag}RDS`,
dbName: `${ownerTag}RDS`, // dbName can only be alpah numeric characters
identifier: rdsName,
username: "admin",
password: cfg.requireSecret("rdspassword"),
password: cfg.requireSecret("rdspassword"), // TODO generate and store this without human intervention
skipFinalSnapshot: true,
vpcSecurityGroupIds: [dbSecurityGroup.id],
dbSubnetGroupName: dbSubnetGroup.name, // Use the subnet group created above
Expand Down
80 changes: 53 additions & 27 deletions unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,67 @@ import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import { createRDS } from "./index";

jest.mock("@pulumi/pulumi", () => ({
...jest.requireActual("@pulumi/pulumi"),
output: jest.fn().mockImplementation((val: any) => val), // Mock output function
jest.mock("@pulumi/aws", () => ({
...jest.requireActual("@pulumi/aws"),
rds: {
Instance: jest.fn().mockImplementation((name, args, opts) => {
return {
id: `${name}-mock-id`,
arn: `${name}-mock-arn`,
};
}),
SubnetGroup: jest.fn().mockImplementation((name, args, opts) => {
return {
name,
subnetIds: ["subnet-12345678", "subnet-87654321"],
};
}),
SecurityGroup: jest.fn().mockImplementation((name, args, opts) => {
return {
id: `${name}-mock-id`,
};
}),
},
ec2: {
SecurityGroup: jest.fn().mockImplementation((name, args, opts) => {
return {
id: `${name}-mock-id`,
};
}),
},
}));

describe("createRDS function", () => {
beforeEach(() => {
jest.clearAllMocks(); // Clear all mocks before each test
jest.clearAllMocks();
});

it("should create an RDS instance with correct security group ingress rules", async () => {
// Mock the output of pulumi.output to return a value that can be used with .apply()
(pulumi.output as jest.Mock).mockReturnValueOnce({
apply: jest.fn().mockResolvedValue(["mock-cidr-block"]), // Mocked CIDR block
});
it("should create an RDS instance with correct configuration", async () => {
// Mock the required configuration variable
jest.spyOn(pulumi.Config.prototype, "requireSecret").mockReturnValueOnce("mock-rds-password");

createRDS(); // Call createRDS function
createRDS();

// Check that SecurityGroup constructor was called with the correct arguments
expect(aws.ec2.SecurityGroup).toHaveBeenCalledWith(
expect.any(String), // Name of the security group
{
vpcId: expect.any(String), // Mocked VPC ID
ingress: [
{
protocol: "tcp",
fromPort: 3306,
toPort: 3306,
cidrBlocks: ["mock-cidr-block"], // Mocked CIDR block
},
],
tags: {
"Owner": expect.any(String), // Mocked owner tag
expect(pulumi.Config.prototype.requireSecret).toHaveBeenCalledWith("project:rdspassword");
expect(aws.rds.Instance).toHaveBeenCalled();
expect(aws.rds.SubnetGroup).toHaveBeenCalled();
expect(aws.ec2.SecurityGroup).toHaveBeenCalledWith(expect.any(String), {
vpcId: expect.any(String),
ingress: [
{
protocol: "tcp",
fromPort: 3306,
toPort: 3306,
cidrBlocks: ["0.0.0.0/0"],
},
}
);
],
});

// Additional check for port 3306 not open to the world
const securityGroupArgs = (aws.ec2.SecurityGroup as jest.Mock).mock.calls[0][1];
const ingressRules = securityGroupArgs.ingress as aws.types.input.ec2.SecurityGroupIngress[];
const rule = ingressRules[0]; // Assuming only one ingress rule is defined

expect(rule.cidrBlocks).not.toContain("0.0.0.0/0");
});
});

0 comments on commit 768b1e3

Please sign in to comment.