Skip to content

Commit

Permalink
Add GCP connections for mirroring (#22)
Browse files Browse the repository at this point in the history
Plus make most installation files less system/platform dependent by sourcing location vars from environment
  • Loading branch information
AHarmlessPyro authored Sep 2, 2022
1 parent 6a1e2c5 commit dbda826
Show file tree
Hide file tree
Showing 31 changed files with 2,950 additions and 499 deletions.
11 changes: 8 additions & 3 deletions backend/src/api/connections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@ import {
import ApiResponseHandler from "api-response-handler"
import { decrypt } from "utils/encryption"
import { delete_connection as delete_connection_request } from "suricata_setup/"
import { ConnectionType } from "@common/enums"

const list_connections = async (req: Request, res: Response) => {
try {
const connections = (await list_connections_service()).map(v => {
delete v.aws.keypair
delete v.aws.access_id
delete v.aws.secret_access_key
if (v.connectionType === ConnectionType.AWS) {
delete v.aws.keypair
delete v.aws.access_id
delete v.aws.secret_access_key
} else if (v.connectionType === ConnectionType.GCP) {
delete v.gcp.key_file
}
return v
})

Expand Down
78 changes: 59 additions & 19 deletions backend/src/api/setup/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { Request, Response } from "express"
import ApiResponseHandler from "api-response-handler"
import { AWS_CONNECTION, STEP_RESPONSE } from "@common/types"
import { AWS_CONNECTION, SSH_INFO, STEP_RESPONSE } from "@common/types"
import { ConnectionType } from "@common/enums"
import { setup } from "suricata_setup"
import "express-session"
import { EC2_CONN } from "suricata_setup/aws-services/create-ec2-instance"
import { VirtualizationType } from "@aws-sdk/client-ec2"
import { save_connection } from "services/connections"
import { deleteKeyFromRedis, getFromRedis } from "suricata_setup/utils"
import {
list_images,
list_machines,
} from "suricata_setup/gcp-services/gcp_setup"

declare module "express-session" {
interface SessionData {
connection_config: Record<
string, // id
{
step?: STEP_RESPONSE["step_number"]
status?: STEP_RESPONSE["status"]
step?: STEP_RESPONSE<ConnectionType>["step_number"]
status?: STEP_RESPONSE<ConnectionType>["status"]
id?: string
type?: ConnectionType
data?: STEP_RESPONSE["data"]
Expand Down Expand Up @@ -53,17 +56,6 @@ export const setup_connection = async (
...resp,
}

if (resp.status === "COMPLETE") {
const {
params: { name },
} = req.body
await save_connection({
conn_meta: req.session.connection_config[id].data as AWS_CONNECTION,
id: id,
name: name,
})
}

delete resp.data

await ApiResponseHandler.success(res, resp)
Expand All @@ -77,23 +69,41 @@ export const aws_os_choices = async (
res: Response,
): Promise<void> => {
const { id } = req.body
const { access_id, secret_access_key, region } =
req.session.connection_config[id].data
const { access_id, secret_access_key, region } = req.session
.connection_config[id].data as STEP_RESPONSE<ConnectionType.AWS>["data"]
let conn = new EC2_CONN(access_id, secret_access_key, region)
let choices = await conn.get_latest_image()
await ApiResponseHandler.success(res, [
[choices.Description, choices.ImageId],
])
}

export const gcp_os_choices = async (
req: Request,
res: Response,
): Promise<void> => {
try {
const { id } = req.body
const { key_file, zone, project } = req.session.connection_config[id]
.data as STEP_RESPONSE<ConnectionType.GCP>["data"]

let choices = await list_images({ key_file, project, zone })
let resp = choices.map(v => [v.description, v.selfLink])
await ApiResponseHandler.success(res, resp)
} catch (err) {
await ApiResponseHandler.error(res, err)
}
}

export const aws_instance_choices = async (
req: Request,
res: Response,
): Promise<void> => {
try {
const { id, specs } = req.body
const { access_id, secret_access_key, virtualization_type, region } =
req.session.connection_config[id].data
const { access_id, secret_access_key, virtualization_type, region } = req
.session.connection_config[id]
.data as STEP_RESPONSE<ConnectionType.AWS>["data"]
let conn = new EC2_CONN(access_id, secret_access_key, region)
let choices = await conn.get_valid_types(
virtualization_type as VirtualizationType,
Expand All @@ -107,6 +117,32 @@ export const aws_instance_choices = async (
ApiResponseHandler.error(res, err)
}
}
export const gcp_instance_choices = async (
req: Request,
res: Response,
): Promise<void> => {
try {
const { id, specs } = req.body
const { key_file, zone, project } = req.session.connection_config[id]
.data as STEP_RESPONSE<ConnectionType.GCP>["data"]

let choices = await list_machines({
key_file,
zone,
project,
minCpu: specs.minCpu,
maxCpu: specs.maxCpu,
minMem: specs.minMem,
maxMem: specs.maxMem,
})
await ApiResponseHandler.success(
res,
choices.map(v => [v.name, v.selfLink]),
)
} catch (err) {
ApiResponseHandler.error(res, err)
}
}

export const get_setup_state = async (req: Request, res: Response) => {
const { uuid } = req.params
Expand All @@ -115,6 +151,10 @@ export const get_setup_state = async (req: Request, res: Response) => {
if (["OK", "FAIL"].includes(resp.success)) {
await deleteKeyFromRedis(uuid)
}
req.session.connection_config[resp.data.id] = {
...req.session.connection_config[resp.data.id],
...resp,
}
delete resp.data
await ApiResponseHandler.success(res, resp)
} catch (err) {
Expand Down
4 changes: 4 additions & 0 deletions backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import { MulterSource } from "multer-source"
import {
aws_instance_choices,
aws_os_choices,
gcp_instance_choices,
gcp_os_choices,
get_setup_state,
setup_connection,
} from "./api/setup"
Expand Down Expand Up @@ -99,6 +101,8 @@ app.post("/api/v1/setup_connection", setup_connection)
app.get("/api/v1/setup_connection/fetch/:uuid", get_setup_state)
app.post("/api/v1/setup_connection/aws/os", aws_os_choices)
app.post("/api/v1/setup_connection/aws/instances", aws_instance_choices)
app.post("/api/v1/setup_connection/gcp/os", gcp_os_choices)
app.post("/api/v1/setup_connection/gcp/instances", gcp_instance_choices)
app.get("/api/v1/list_connections", list_connections)
app.get("/api/v1/list_connections/:uuid", get_connection_for_uuid)
app.get(
Expand Down
31 changes: 29 additions & 2 deletions backend/src/models/connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ import {
BeforeInsert,
} from "typeorm"
import { ConnectionType } from "@common/enums"
import { AWS_CONNECTION, ENCRYPTED_AWS_CONNECTION__META } from "@common/types"
import {
AWS_CONNECTION,
ENCRYPTED_AWS_CONNECTION__META,
ENCRYPTED_GCP_CONNECTION__META,
GCP_CONNECTION,
SSH_INFO,
} from "@common/types"
import { encrypt, generate_iv } from "utils/encryption"

@Entity()
Expand All @@ -29,11 +35,17 @@ export class Connections extends BaseEntity {
name: string

@Column({ nullable: true, type: "jsonb" })
aws?: AWS_CONNECTION
aws?: AWS_CONNECTION & SSH_INFO

@Column({ nullable: true, type: "jsonb" })
aws_meta?: ENCRYPTED_AWS_CONNECTION__META

@Column({ nullable: true, type: "jsonb" })
gcp?: GCP_CONNECTION

@Column({ nullable: true, type: "jsonb" })
gcp_meta?: ENCRYPTED_GCP_CONNECTION__META

@BeforeInsert()
beforeInsert() {
let key = process.env.ENCRYPTION_KEY
Expand Down Expand Up @@ -75,6 +87,21 @@ export class Connections extends BaseEntity {
secret_access_key_iv: sa_key_iv.toString("base64"),
}
}
} else if (this.connectionType == ConnectionType.GCP && this.gcp) {
// Encrypt GCP Key File
let key_file_iv = generate_iv()
let { encrypted: encrypted_k, tag: tag_k } = encrypt(
this.gcp.key_file,
encryptionKey,
key_file_iv,
)
this.gcp.key_file = encrypted_k
if (!this.gcp_meta) {
this.gcp_meta = {
key_file_tag: tag_k.toString("base64"),
key_file_iv: key_file_iv.toString("base64"),
}
}
}
}
}
80 changes: 75 additions & 5 deletions backend/src/services/connections/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { ConnectionType } from "@common/enums"
import { AWS_CONNECTION } from "@common/types"
import { AWS_CONNECTION, GCP_CONNECTION, SSH_INFO } from "@common/types"
import { AppDataSource } from "data-source"
import Error500InternalServer from "errors/error-500-internal-server"
import { Connections } from "models"

const save_connection = async ({
const save_connection_aws = async ({
conn_meta,
name,
id,
}: {
conn_meta: AWS_CONNECTION
conn_meta: AWS_CONNECTION & SSH_INFO
name: string
id: string
}) => {
Expand Down Expand Up @@ -52,7 +52,7 @@ const save_connection = async ({
remote_machine_url,
keypair_name,
keypair_id,
} as AWS_CONNECTION
} as AWS_CONNECTION & SSH_INFO
conn.connectionType = ConnectionType.AWS
conn.uuid = id
conn.name = name
Expand All @@ -64,6 +64,74 @@ const save_connection = async ({
throw new Error500InternalServer(err)
}
}
const save_connection_gcp = async ({
conn_meta,
name,
id,
}: {
conn_meta: GCP_CONNECTION
name: string
id: string
}) => {
const {
key_file,
project,
zone,
network_url,
ip_range,
source_subnetwork_url,
firewall_rule_url,
destination_subnetwork_url,
router_url,
machine_type,
source_image,
image_template_url,
instance_url,
managed_group_url,
health_check_url,
backend_service_url,
forwarding_rule_url,
source_instance_url,
packet_mirror_url,
source_instance_name,
source_private_ip,
} = conn_meta
const conn = new Connections()

conn.gcp = {
key_file,
project,
zone,
network_url,
ip_range,
source_subnetwork_url,
firewall_rule_url,
destination_subnetwork_url,
router_url,
machine_type,
source_image,
image_template_url,
instance_url,
managed_group_url,
health_check_url,
backend_service_url,
forwarding_rule_url,
source_instance_url,
packet_mirror_url,
source_instance_name,
source_private_ip,
} as GCP_CONNECTION
conn.connectionType = ConnectionType.GCP
conn.uuid = id
conn.name = name
try {
const connectionRepository = AppDataSource.getRepository(Connections)
await connectionRepository.save(conn)
} catch (err) {
console.error(`Error in saving connection: ${err}`)
throw new Error500InternalServer(err)
}
}

const list_connections = async () => {
try {
Expand All @@ -77,6 +145,7 @@ const list_connections = async () => {
"conn.updatedAt",
"conn.connectionType",
"conn.aws",
"conn.gcp",
])
.getMany()
return resp
Expand Down Expand Up @@ -149,7 +218,8 @@ const delete_connection_for_uuid = async ({ uuid }) => {
}
}
export {
save_connection,
save_connection_aws,
save_connection_gcp,
list_connections,
get_connection_for_uuid,
update_connection_for_uuid,
Expand Down
Loading

0 comments on commit dbda826

Please sign in to comment.