Skip to content

Commit 613c04c

Browse files
feat(mbe, ebe): dockerize mbe & ebe
Ticket: WP-4681
1 parent ac13c78 commit 613c04c

File tree

9 files changed

+273
-4
lines changed

9 files changed

+273
-4
lines changed

.dockerignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.git
2+
node_modules
3+
npm-debug.log
4+
yarn-debug.log
5+
yarn-error.log
6+
.env
7+
*.md
8+
.DS_Store
9+
.vscode
10+
.idea
11+
*.log
12+
coverage/
13+
test/
14+
__tests__/
15+
*.test.*

Dockerfile

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# syntax=docker/dockerfile:1.4
2+
3+
# Build stage
4+
FROM node:22.1.0-alpine@sha256:487dc5d5122d578e13f2231aa4ac0f63068becd921099c4c677c850df93bede8 AS builder
5+
6+
# Set build-time variables for reproducibility
7+
ARG NODE_ENV=development
8+
ARG BUILD_VERSION=dev
9+
ARG BUILD_DATE=unknown
10+
ARG VCS_REF=unknown
11+
ARG PORT=3081
12+
13+
# Set environment variables
14+
ENV NODE_ENV=${NODE_ENV} \
15+
NODE_VERSION=22.1.0
16+
17+
# Set build-time labels
18+
LABEL org.opencontainers.image.created=${BUILD_DATE} \
19+
org.opencontainers.image.version=${BUILD_VERSION} \
20+
org.opencontainers.image.revision=${VCS_REF}
21+
22+
# Set consistent timezone and locale
23+
ENV TZ=UTC \
24+
LANG=C.UTF-8
25+
26+
# Create app directory
27+
WORKDIR /usr/src/app
28+
29+
# Install build dependencies
30+
RUN --mount=type=cache,target=/var/cache/apk \
31+
apk add --no-cache \
32+
python3 \
33+
make \
34+
g++ \
35+
gcc \
36+
linux-headers
37+
38+
# Copy dependency files
39+
COPY package.json yarn.lock ./
40+
41+
# Install dependencies with cache mount
42+
RUN --mount=type=cache,target=/usr/src/app/.yarn-cache \
43+
yarn install --frozen-lockfile --production=false --cache-folder /usr/src/app/.yarn-cache && \
44+
yarn cache clean && \
45+
rm -rf /usr/src/app/.yarn-cache/*
46+
47+
# Copy source code
48+
COPY . .
49+
50+
# Build TypeScript code with deterministic output
51+
RUN yarn build
52+
53+
FROM node:22.1.0-alpine@sha256:487dc5d5122d578e13f2231aa4ac0f63068becd921099c4c677c850df93bede8 AS production
54+
55+
# Set build-time labels
56+
LABEL org.opencontainers.image.created=${BUILD_DATE} \
57+
org.opencontainers.image.version=${BUILD_VERSION} \
58+
org.opencontainers.image.revision=${VCS_REF}
59+
60+
# Set runtime environment
61+
ENV NODE_ENV={NODE_ENV} \
62+
TZ=UTC \
63+
LANG=C.UTF-8
64+
65+
WORKDIR /usr/src/app
66+
67+
# Create non-root user, certificate directory and logs directory
68+
RUN addgroup -S bitgo && \
69+
adduser -S bitgo -G bitgo && \
70+
mkdir -p /app/certs && \
71+
mkdir -p /usr/src/app/logs && \
72+
chown -R bitgo:bitgo /app/certs && \
73+
chown -R bitgo:bitgo /usr/src/app && \
74+
chmod 750 /app/certs && \
75+
chmod 750 /usr/src/app/logs
76+
77+
# Copy only necessary files from builder
78+
COPY --from=builder --chown=bitgo:bitgo /usr/src/app/dist ./dist
79+
COPY --from=builder --chown=bitgo:bitgo /usr/src/app/node_modules ./node_modules
80+
COPY --from=builder --chown=bitgo:bitgo /usr/src/app/bin ./bin
81+
COPY --from=builder --chown=bitgo:bitgo /usr/src/app/package.json .
82+
83+
USER bitgo
84+
85+
# Expose port from build arg
86+
EXPOSE ${PORT}
87+
88+
# Start the application using the binary
89+
CMD ["./bin/enclaved-bitgo-express"]

README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,74 @@ ALLOW_SELF_SIGNED=false \
168168
yarn start
169169
```
170170

171+
## Container Deployment with Podman
172+
173+
First, build the container image:
174+
175+
```bash
176+
# For Master Express (default port 3081)
177+
yarn container:build
178+
179+
# For Enclaved Express (port 3080)
180+
yarn container:build --build-arg PORT=3080
181+
```
182+
183+
For local development, you'll need to run both the Enclaved Express and Master Express containers:
184+
185+
```bash
186+
# Start Enclaved Express container
187+
podman run -d \
188+
-p 3080:3080 \
189+
-v $(pwd)/certs:/app/certs:Z \
190+
-e APP_MODE=enclaved \
191+
-e BIND=0.0.0.0 \
192+
-e TLS_MODE=mtls \
193+
-e TLS_KEY_PATH=/app/certs/enclaved-express-key.pem \
194+
-e TLS_CERT_PATH=/app/certs/enclaved-express-cert.pem \
195+
-e KMS_URL=host.containers.internal:3000 \
196+
-e NODE_ENV=development \
197+
-e ALLOW_SELF_SIGNED=true \
198+
bitgo-onprem-express
199+
200+
# View logs
201+
podman logs -f <container_id>
202+
203+
# Test the endpoint (note: using https)
204+
curl -k -X POST https://localhost:3080/ping
205+
206+
# Start Master Express container
207+
podman run -d \
208+
-p 3081:3081 \
209+
-v $(pwd)/certs:/app/certs:Z \
210+
-e APP_MODE=master-express \
211+
-e BIND=0.0.0.0 \
212+
-e TLS_MODE=mtls \
213+
-e TLS_KEY_PATH=/app/certs/test-ssl-key.pem \
214+
-e TLS_CERT_PATH=/app/certs/test-ssl-cert.pem \
215+
-e ENCLAVED_EXPRESS_URL=https://host.containers.internal:3080 \
216+
-e ENCLAVED_EXPRESS_CERT=/app/certs/enclaved-express-cert.pem \
217+
-e ALLOW_SELF_SIGNED=true \
218+
bitgo-onprem-express
219+
220+
# View logs
221+
podman logs -f <container_id>
222+
223+
# Test the endpoints (note: using https and mTLS)
224+
# For Enclaved Express
225+
curl -k --cert certs/test-ssl-cert.pem --key certs/enclaved-express-key.pem -X POST https://localhost:3080/ping
226+
227+
# For Master Express
228+
curl -k --cert certs/test-ssl-cert.pem --key certs/test-ssl-key.pem -X POST https://localhost:3081/ping
229+
230+
# Test the connection
231+
curl -k -X POST https://localhost:3081/ping/enclavedExpress
232+
```
233+
234+
Notes:
235+
- `host.containers.internal` is a special DNS name that resolves to the host machine from inside containers
236+
- The `:Z` option in volume mounts is specific to SELinux-enabled systems and ensures proper volume labeling
237+
- The logs directory will be created with appropriate permissions if it doesn't exist
238+
171239
## API Endpoints
172240

173241
### Enclaved Express (Port 3080)

certs/enclaved-express-cert.pem

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDCTCCAfGgAwIBAgIUbE+vqSu9IgPoLJncJqX5aiXh2GkwDQYJKoZIhvcNAQEL
3+
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MDUzMDIwMDgxNVoXDTI2MDUz
4+
MDIwMDgxNVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
5+
AAOCAQ8AMIIBCgKCAQEAsK1g8ts/QRdEHVnmiZSijvtKl08yf13JWY0yksJW0O6x
6+
mrt2uotvONxMNKhGtS+hPjcJ2OC7fCyift8oaCDs7PfIXjVNcN2zRKPci8ihNWvQ
7+
XrYGLTvL9EVHpH7CdlJU43BTaeFusH+k/qv2pW5WQnz13ULdq7yvnDFvJAeahm9X
8+
ptvr9RX9f8Aki0Y82Zi04PCiaHdqBPPl1OfHi+brf4xl7pQUq7Pub94/IDywe+QK
9+
lGFPQ0exSVm5X/7hWv/AxqEFa/Bqb6Uw0qatVqhrgLEHlLUYVXs9NDNXm+865+aT
10+
kvW2dnBpTVRZjnXO+N+BwSj+PfI28RqMXsmIhraN4QIDAQABo1MwUTAdBgNVHQ4E
11+
FgQUnsZxpWiuxqDq/1kV12rMos4NN/cwHwYDVR0jBBgwFoAUnsZxpWiuxqDq/1kV
12+
12rMos4NN/cwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAsAX4
13+
CCEsIVrKQKJKluEDqOFiuKg0SSe4xVqlSW9vy9z3UYLfOpw14EtB6Lzbtgw7z47w
14+
AnZZS99Zzn3tbYd06/X+b3jThF5TU1gqBcYDCC9HCd9xpmQEC7Ss1Xa88ubjuh+U
15+
E/7xN5xRt85S07VihJWscfY7JCUAELBo3gDCZLfgHjw8xMfPRceE36rkc5B2p60b
16+
WEmmOBWjrSboMOfocasBTUVUMDvGgmxEGEmKgTYshr5lWKcIteisbZi7+OZlkflp
17+
PUZNu5DUyQyjftr2EShndaceZrjgXt6ezoyQBVgPRA+N+NAJn+uBr3B3nZZb/mft
18+
n3XsbtsAAoU49kEVOg==
19+
-----END CERTIFICATE-----

certs/enclaved-express-key.pem

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCwrWDy2z9BF0Qd
3+
WeaJlKKO+0qXTzJ/XclZjTKSwlbQ7rGau3a6i2843Ew0qEa1L6E+NwnY4Lt8LKJ+
4+
3yhoIOzs98heNU1w3bNEo9yLyKE1a9BetgYtO8v0RUekfsJ2UlTjcFNp4W6wf6T+
5+
q/alblZCfPXdQt2rvK+cMW8kB5qGb1em2+v1Ff1/wCSLRjzZmLTg8KJod2oE8+XU
6+
58eL5ut/jGXulBSrs+5v3j8gPLB75AqUYU9DR7FJWblf/uFa/8DGoQVr8GpvpTDS
7+
pq1WqGuAsQeUtRhVez00M1eb7zrn5pOS9bZ2cGlNVFmOdc7434HBKP498jbxGoxe
8+
yYiGto3hAgMBAAECggEACrbTnJwBJQBf3WvN7Y/5n7Qg3ODXo3Ow5Iu0gm6N9z5S
9+
akYYuCKr4bCHtTXIkUT3K/UIgCzOEdoJwf85zb7EFMbIpuCSoVfrKYF1EXZe7a9r
10+
w81EE0rUs9aJDAeyi/Gy5iwHUvIcf/rtqugLcr194QBU+fsLwwC+oY6POonKLCwg
11+
gXMxRJKx+tvp86x6s7FU8+vi40L/mGbCC1Bl1YqraVp8nT17ICivlcHVZESxCcKN
12+
tCAY+xKK+zH+s5sHAQvM4OlGEvCeT1VISlw/VqkODxcGzMGUc+mbnGtWvDcYm9Pa
13+
54F29QapkdUwBVnucpTICenaMrLr19H9l6Zgvfvx1QKBgQDnHHeGnSD1bpZUhIUt
14+
2vIQpj7o26zsx472h9PmqIZwODpcYSfw8MknymXVnL78gdHqVDL0mgj59zemUpC7
15+
CR9RJAlV7/3TghUPdDFQ/SGj9+xGG/L/HNyy6bQeLIZiGOlURcdFqAtKCIk+51oK
16+
eTDCOuy3Ijrq6F6FbYnkXHmwcwKBgQDDtDdCo9EjnyiZ1qGOx5jLRNbGVlN77QFS
17+
tSmegODAwfLQpm4c4fE2WnzeWlNXnzs8GRLSRASXIYunjQdvgpX1KTpffZPoSP3k
18+
tvL8cbh1zk7X8cmvkrVJjcpn/ecWPgeHGV6MjuhxqhaVoEMjFsKRqQaSQ7r/gZsm
19+
Vba82tuXWwKBgHFlSlBGcJF7/U7i5uWk8/ivWVav0p0rHT5hTttx/OS68ge5s/tI
20+
aaqYaHbzPdJvcCvlvEq/+X+MiUWWZWUgCLmrUNlVs9k/jk3S2Q+/4+2sC8YqmIQM
21+
CU3P1YyolBc12eZ7hlbrKP7eSVkP8uIIrJ/ggZ0psnboJNia8nmV1i95AoGAPNWE
22+
Z/6sQDp1UHzbc5qv8F/Rs42aHeeqhZ8y9MZzFvgzFpDloazKYm72adgCGDazHxdc
23+
NmhWVPRkiQzZxtv86VyLfKt4krg91B7aoYZoJJahA5dxblZYbCjbRkAy2UMm6+QC
24+
9AZoUwzgQFq1A+9LRCQamtTbCBmttNjoGQSfRgkCgYEAi03ZXB+B0/4C2HRUz/GQ
25+
6moLgB7FzC4MLY2KUDeiP+3zBPnfbGQM0OgPYu7OOWPC6lebS4C6DuPCTOSW1z8u
26+
f4FeVSKGrofPx+DmEvUMsUQ5TvjRPwNL40PVlrdxytZi6nV01GveScPfljvQUd2r
27+
DRaZg+YgV9Yl6wi8y2G5RD0=
28+
-----END PRIVATE KEY-----

certs/test-ssl-cert.pem

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDCTCCAfGgAwIBAgIUYN0EUBLwq7uoLwDuTx7gDW0HS2UwDQYJKoZIhvcNAQEL
3+
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MDUxNDIxMTUzMVoXDTI2MDUx
4+
NDIxMTUzMVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
5+
AAOCAQ8AMIIBCgKCAQEAmxdCF7xCJcE6yyG+wrdhHMwRiQxbhDLW/hiKQcO/nn7z
6+
QMM9LAV04+WG5LCmm0ygocbfXXhfWn5D6SSSESKTb8dbSj6AJbLSmYjA5vDSzh9R
7+
rO9GzNTDCDne+epo+rN4BOjGh7K83naLei/bEfmklMp7x+TyoBC8Ps/3Eq4HOJfd
8+
UzgV2L3oC/4dCbAnkgK2zanL8KEaH6aM0HytIaqMFYLBs2t8s7HHHcSEadHfjlJu
9+
GwTmTS0nVhJBWYJvF6Pv/SwLFuSo93TJybaMMUSF3oJK35NEYXg6EtibJLUC9RvX
10+
FVLytRA5z+x7FBnGBdi4ctMseecokV4u15ePCB3MXwIDAQABo1MwUTAdBgNVHQ4E
11+
FgQUxHrQZFFBfTfuXeOOoXmHZQ8E6rswHwYDVR0jBBgwFoAUxHrQZFFBfTfuXeOO
12+
oXmHZQ8E6rswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAj0hy
13+
bwWh2B26cR0ADhuDC0MtGPBH0BrHypJEZ96nUPTY4oxRrjZusgdq60ooqsNyIW6k
14+
cZHkajC/O0V6hnV4yMhLE8ZwA+31iyQakonpT5N1OON4Ddv9Bfvx8xOn75x/+RP+
15+
GlAa31XxivryIi/5y7MEI0PwU34T/6bbMWdBaFRQtbuIXJ/90AZ0fBwIV0vJWjaO
16+
1DriZAJe7hl63ZUw6CsfutpoyKkanF5GQB2CpolR3t1oeHwuDbZ550p1g2XFB6UI
17+
9W+zlggQFeAnthzMoi3erO4sQ3j2b15QLZbk1HXHZcn3+89QcvdUcpG0u51bZdFW
18+
SJ+bnT3TZ9H+szoa1w==
19+
-----END CERTIFICATE-----

certs/test-ssl-key.pem

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCbF0IXvEIlwTrL
3+
Ib7Ct2EczBGJDFuEMtb+GIpBw7+efvNAwz0sBXTj5YbksKabTKChxt9deF9afkPp
4+
JJIRIpNvx1tKPoAlstKZiMDm8NLOH1Gs70bM1MMIOd756mj6s3gE6MaHsrzedot6
5+
L9sR+aSUynvH5PKgELw+z/cSrgc4l91TOBXYvegL/h0JsCeSArbNqcvwoRofpozQ
6+
fK0hqowVgsGza3yzsccdxIRp0d+OUm4bBOZNLSdWEkFZgm8Xo+/9LAsW5Kj3dMnJ
7+
towxRIXegkrfk0RheDoS2JsktQL1G9cVUvK1EDnP7HsUGcYF2Lhy0yx55yiRXi7X
8+
l48IHcxfAgMBAAECggEAAft4dHXgi+ZTX7iiXTobe1MUakxbzcMZ7QzX6jfxTA+o
9+
APeTNuvURFFxDvKUaT8VJ9wzNgOi3F+UHffCB4a0nGTPmDxXm6O/KLKPHKSOso8Y
10+
ln2cdGPHy7l0TdIe3g113EI0FL9GcLrSf5D7Bi4gWhKDJdlETKLKH9dn+2IkD3zE
11+
VM+7pwqYV6XZu2GuZ1om1JE+Hx2D5YLIuRCON0RKpzCLikmM7VErA7sjy7LsCSh9
12+
ty5n1s9GoNtF+YuOD9WeMWGDonMyJdYWTsmFYoT+LF7W+GHoEwvYm9595QuNnxVx
13+
KQ4P5oKm/EfcSiBhCC8BdCIGch9tQPT7c/syVhHG4QKBgQDTdUVW7rJNnLtHgWF2
14+
ubjh9b3ZfxPuTEu6ueKON5XXvSgfsMBNgCxwkemefGJ6xIjDu+swud+2H33Tqj23
15+
GMMTZ1JEzNYINO1m/laSAK+DcL81q4sLLlJTbBhYeE6FBeEO1hAmU2IiYrgU6zbO
16+
eyo4ysXtFJdnHSR9PHjZpt/cMQKBgQC7wmxw2UNPlmwTzl6l7z5DqYxizIfezb9l
17+
pIYrmcD92asxZKPi1soz8PcOn30gGmjtZn/7FkXFHSRsNknUmqJOEbZrvNCcKndz
18+
O+RbKGs8FAKlyog8k3CTToAng4PutsYrAuK/kx84P9FPCgTxdhejRMkfkSebCJQH
19+
fmXRnlRdjwKBgQCm2Drz0rcBIg9q5hz+zp+gOoOnnusc9TozhQPLbvReGzQTfSTe
20+
gamO0LJiiIYzk+rNdfKmqaJoUwS3A/ZaB8G0B6wT+QNPymMfBsNLxBq4PTfBoy68
21+
jboLdJjpBVP/BZqEWEa51sTxmK7iYo0F8oxn7yaoX7zucUIfRp2cLl0noQKBgB+K
22+
RG8cgAshiJw3IX0cWEhDdfquwvAxfcJURdmTJXE/HFvavREA5cyd4NKLBhjbdt7S
23+
RhNmpWe8Qn8PC430P+l/XjZw7FYfaBtqZyzM+F6KOfuhrwsF9XY5TJvWotX5zAYz
24+
oOVvkGIBjmaJl1T8cnIRvvtXheCsKzmrCO2SfDePAoGAM1ToKwXSeZEm2Kyf/PV9
25+
74lvBKYP5LP+pSmrcTq9jUbPQy3KmlhBi+kyhVK+2Awmh0J9tzu83C8lWR25L4mc
26+
/Uwjhv2KwmvJKyZ4/5t/oMZ+BsZERSHj39juLNW+UL82M2heM5tv5/MI779SAmzl
27+
VJMN4N1x+L7408dEGu0j2ds=
28+
-----END PRIVATE KEY-----

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"test:coverage": "nyc mocha --require ts-node/register 'src/**/__tests__/**/*.test.ts'",
1616
"lint": "eslint --quiet .",
1717
"generate-test-ssl": "openssl req -x509 -newkey rsa:2048 -keyout test-ssl-key.pem -out test-ssl-cert.pem -days 365 -nodes -subj '/CN=localhost'",
18-
"generate:openapi:masterExpress": "npx @api-ts/openapi-generator --name @bitgo/master-bitgo-express ./src/masterBitgoExpress/routers/index.ts > masterBitgoExpress.json"
18+
"generate:openapi:masterExpress": "npx @api-ts/openapi-generator --name @bitgo/master-bitgo-express ./src/masterBitgoExpress/routers/index.ts > masterBitgoExpress.json",
19+
"container:build": "podman build -t bitgo-onprem-express ."
1920
},
2021
"dependencies": {
2122
"@api-ts/io-ts-http": "^3.2.1",

src/masterBitgoExpress/routers/enclavedExpressHealth.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ import { responseHandler } from '../../shared/middleware';
1212
const PingEnclavedResponse: HttpResponse = {
1313
200: t.type({
1414
status: t.string,
15-
// TODO: Move to common definition between enclavedExpress and masterExpress
1615
enclavedResponse: t.type({
17-
message: t.string,
16+
status: t.string,
1817
timestamp: t.string,
1918
}),
2019
}),
@@ -79,7 +78,10 @@ export function createEnclavedExpressRouter(
7978

8079
return Response.ok({
8180
status: 'Successfully pinged enclaved express',
82-
enclavedResponse: response.body,
81+
enclavedResponse: {
82+
status: response.body.status,
83+
timestamp: response.body.timestamp,
84+
},
8385
});
8486
} catch (error) {
8587
logger.error('Failed to ping enclaved express:', { error });

0 commit comments

Comments
 (0)