paint-brush
Build DevOps for Secure Auth API Gateway using Nodejs, Aptible Terraform and Redisby@wise4rmgod
1,704 reads
1,704 reads

Build DevOps for Secure Auth API Gateway using Nodejs, Aptible Terraform and Redis

by Wisdom NwokochaJanuary 8th, 2024
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Building a secure and scalable API gateway is crucial to modern software development. In this context, Node.js, Aptible Terraform, and Redis are three powerful tools that can be used to create a secure and scalable API gateway.

Company Mentioned

Mention Thumbnail
featured image - Build DevOps for Secure Auth API Gateway using Nodejs, Aptible Terraform and Redis
Wisdom Nwokocha HackerNoon profile picture

Building a secure and scalable API gateway is crucial to modern software development. In this context, Node.js, Aptible Terraform, and Redis are three powerful tools that can be used to create a secure and scalable API gateway.


With Node.js, you can build fast and efficient server-side applications, while Aptible Terraform allows you to manage your Aptible resources directly from Terraform, enabling infrastructure as code (IaC).


Redis is an open-source, in-memory data structure store that can be used as a database, cache, and message broker.


Together, these tools can help you create a secure and scalable API gateway that can handle many requests while ensuring your data's security.

Prerequisites:

To build a secure and scalable API gateway using Node.js, Aptible Terraform, and Redis, you will need the following prerequisites:


  • Node.js: A powerful JavaScript runtime that forms the backend powerhouse with many authentication libraries.

  • Aptible: A serverless platform simplifying deployments, scaling, and security management for Node.js applications. Basic Aptible knowledge is required.

  • Redis: A lightning-fast in-memory database that acts as the cache and stores crucial authentication data like tokens and user sessions.

  • RedisInsight: A graphical user interface for Redis that allows you to visualize and interact with your Redis data. RedisInsight should be installed and running on your local machine.

  • Terraform: An open-source infrastructure as code (IaC) tool that allows you to manage your infrastructure safely and repeatedly. Basic Terraform knowledge is required.

  • Docker: A containerization platform that packages your application and its dependencies into a single container. Basic Docker knowledge is required.


Initialize Node.js Project

  • Create a new directory for your project and initialize the Node.js project by running this command:
npm init -y


  • Install required packages:
npm install express redis body-parser jsonwebtoken

Setting Up Express Server with Authentication

  • Create an index.js file in your project directory.
  • Configure an Express server:
const express = require('express');

Set Up Redis for Data Storage

Ensure Redis is installed and running on your system.

  • Redis Client Setup:
const redisClient = new Redis();

This code initializes a Redis client that connects to the default Redis server running on localhost at port 6379.


It uses the Redis() constructor from the Redis library to create the client.

redisClient.on("connect", () => {...}); and redisClient.on("error", (err) => {...}); are event listeners that handle events when the Redis client successfully connects or encounters an error during the connection.


  • Express Middleware Setup:
app.use(bodyParser.json());

This sets up the Express app to use the bodyParser.json() middleware, allowing it to parse incoming JSON requests.


  • Registration Endpoint (POST '/register'):
app.post("/register", (req, res) => {
  const { username, password, email } = req.body;
  // Perform validation checks

  // Simulate storing user data in Redis
  redisClient.hmset(
    `user:${username}`,
    ["password", password, "email", email],
    (err, reply) => {
      if (err) {
        console.error(err);
        return res.status(500).json({ error: "Failed to register user" });
      }
      const token = jwt.sign({ username }, "your_secret_key", {
        expiresIn: "1h",
      });
      return res.json({ message: "User registered successfully", token });
    }
  );
});

This endpoint handles the registration of a user. It retrieves username, password, and email from the request body, performs validation checks, and then simulates storing user data in Redis using redisClient.hmset().


  • Login Endpoint (POST '/login'):
app.post("/login", (req, res) => {
  const { username, password } = req.body;
  // Validate user credentials
  redisClient.hget(`user:${username}`, "password", (err, reply) => {
    if (err || reply !== password) {
      return res.status(401).json({ error: "Invalid credentials" });
    }
    // Assuming successful authentication, generate a JWT token
    const token = jwt.sign({ username }, "your_secret_key", {
      expiresIn: "1h",
    });
    return res.json({ message: "Login successful", token });
  });
});

This endpoint handles user login. It validates the user's credentials by retrieving the stored password from Redis using redisClient.hget().

If the credentials are valid, it generates a JWT token for authentication.


  • Protected Route (GET '/protected'):
app.get("/protected", verifyToken, (req, res) => {
  // If the token is verified, allow access to the protected route
  return res.json({ message: "Access granted to protected route" });
});

This is an example of a protected route that requires a Bearer token for access. It uses the verifyToken middleware function to verify the token before allowing access to the route.


  • verifyToken Middleware Function:
function verifyToken(req, res, next) {
  const bearerHeader = req.headers["authorization"];
  if (typeof bearerHeader !== "undefined") {
    const bearerToken = bearerHeader.split(" ")[1]; // Extract token from header
    req.token = bearerToken;
    jwt.verify(req.token, "your_secret_key", (err, authData) => {
      if (err) {
        return res.status(403).json({ error: "Forbidden" });
      }
      // If token is valid, proceed to the next middleware/route handler
      next();
    });
  } else {
    // If no token provided, return Forbidden
    return res.status(403).json({ error: "Forbidden" });
  }
}

This middleware function checks for a Bearer token in the Authorization request's header. If a valid token is present, it verifies it using jwt.verify() and allows access to the protected routes.

Otherwise, it returns a Forbidden error.


  • Server Listening:
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

This code starts the Express server, listening on the specified PORT, and logs a message to the console once the server is running.


Complete code:


const express = require("express");
const bodyParser = require("body-parser");
const Redis = require("ioredis");
const jwt = require("jsonwebtoken");

const app = express();
const PORT = process.env.PORT || 3000;

// Redis client setup to connect to a local Redis instance
const redisClient = new Redis(); // Connects to default localhost:6379

redisClient.on("connect", () => {
  console.log("Connected to Redis...");
});
redisClient.on("error", (err) => {
  console.error("Redis error:", err);
});

app.use(bodyParser.json());

// Routes
// Registration endpoint
app.post("/register", (req, res) => {
  const { username, password, email } = req.body;
  // Perform validation checks

  // Simulate storing user data in Redis
  redisClient.hmset(
    `user:${username}`,
    ["password", password, "email", email],
    (err, reply) => {
      if (err) {
        console.error(err);
        return res.status(500).json({ error: "Failed to register user" });
      }
      const token = jwt.sign({ username }, "your_secret_key", {
        expiresIn: "1h",
      });
      return res.json({ message: "User registered successfully", token });
    }
  );
});

// Login endpoint requiring a Bearer token for authentication
app.post("/login", (req, res) => {
  const { username, password } = req.body;
  // Validate user credentials
  redisClient.hget(`user:${username}`, "password", (err, reply) => {
    if (err || reply !== password) {
      return res.status(401).json({ error: "Invalid credentials" });
    }
    // Assuming successful authentication, generate a JWT token
    const token = jwt.sign({ username }, "your_secret_key", {
      expiresIn: "1h",
    });
    return res.json({ message: "Login successful", token });
  });
});

// Protected route example - requires a Bearer token for access
app.get("/protected", verifyToken, (req, res) => {
  // If the token is verified, allow access to the protected route
  return res.json({ message: "Access granted to protected route" });
});

// Middleware function to verify the Bearer token in the Authorization header
function verifyToken(req, res, next) {
  const bearerHeader = req.headers["authorization"];
  if (typeof bearerHeader !== "undefined") {
    const bearerToken = bearerHeader.split(" ")[1]; // Extract token from header
    req.token = bearerToken;
    jwt.verify(req.token, "your_secret_key", (err, authData) => {
      if (err) {
        return res.status(403).json({ error: "Forbidden" });
      }
      // If token is valid, proceed to the next middleware/route handler
      next();
    });
  } else {
    // If no token provided, return Forbidden
    return res.status(403).json({ error: "Forbidden" });
  }
}

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});


Run the Server

Start the Redis server:

redis-server


Response:

3444:C 07 Jan 2024 16:40:21.983 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
3444:C 07 Jan 2024 16:40:21.983 * Redis version=7.2.3, bits=64, commit=00000000, modified=0, pid=3444, just started
3444:C 07 Jan 2024 16:40:21.983 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
3444:M 07 Jan 2024 16:40:21.984 * monotonic clock: POSIX clock_gettime
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 7.2.3 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                  
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 3444
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           https://redis.io       
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

3444:M 07 Jan 2024 16:40:21.985 # WARNING: The TCP backlog setting of 511 cannot be enforced because kern.ipc.somaxconn is set to the lower value of 128.
3444:M 07 Jan 2024 16:40:21.985 * Server initialized
3444:M 07 Jan 2024 16:40:21.986 * Loading RDB produced by version 7.2.3
3444:M 07 Jan 2024 16:40:21.986 * RDB age 67145 seconds
3444:M 07 Jan 2024 16:40:21.986 * RDB memory usage when created 1.38 Mb
3444:M 07 Jan 2024 16:40:21.986 * Done loading RDB, keys loaded: 3, keys expired: 0.
3444:M 07 Jan 2024 16:40:21.986 * DB loaded from disk: 0.001 seconds
3444:M 07 Jan 2024 16:40:21.986 * Ready to accept connections tcp


Open a new terminal, then start the Node.js server:

node app.js


Response:

Server running on port 3000
Connected to Redis...


Test the Endpoints

Use tools like curl or Postman to test the registration and login endpoints. Ensure you provide valid JSON data for registration (/register) and login (/login) endpoints.


API Documentation

  • Register a User

Send a POST request to http://localhost:3000/register with the following body (example):

{
  "username": "example_user",
  "password": "example_password",
  "email": "[email protected]"
}


Response:

{
    "message": "User registered successfully",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImV4YW1wbGVfdXNlciIsImlhdCI6MTcwNDU2ODA3OSwiZXhwIjoxNzA0NTcxNjc5fQ.tXernOwDwtYI3iJycBKYTcShalFEcFgE6VFFjbCqtsY"
}


  • Login and Retrieve the Token

Send a POST request to http://localhost:3000/login with the user's credentials in the body:

{
  "username": "example_user",
  "password": "example_password"
}


Response:

{
    "message": "Login successful",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Indpc2RvbSIsImlhdCI6MTcwNDU2NzkzNSwiZXhwIjoxNzA0NTcxNTM1fQ.CZm0yLgA0BsfESGBORdrTLtQ5Kw3SIxSc8PuAaYBRV4"
}


View the Redis database info locally:

RedisInsight offers a comprehensive view of the Redis database, allowing users to explore and analyze the database's contents.


  • Open redisinsight

Click on the Database Alias value that is 127.0.0.1:6379

Redisinsight database alias.

  • Click on an existing data.

For this tutorial, I clicked on the first value, that is user:example_user

Existing data in the database.

Then, this screen will open with more details.

More details.

Dockerize Your Node.js Application:

You need to have a Docker Hub account. If you haven't created one yet, sign up at Docker Hub.

Ensure you have Docker installed and running on your local machine.


  • Create a Dockerfile in the root directory of your Node.js project.
# Use an official Node.js runtime as the base image
FROM node:16

# Set the working directory in the container
WORKDIR /usr/src/app

# Copy package.json and package-lock.json to the working directory
COPY package*.json ./

# Install app dependencies
RUN npm install

# Copy the rest of the application files to the working directory
COPY . .

# Expose the port the app runs on
EXPOSE 3000

# Define the command to run the app
CMD ["node", "blog.js"]


The folder structure after adding the Dockerfile

Folder structure.


  • Tag your Docker image: Open your terminal , navigate to the root directory of your Node.js application, where your Dockerfile is located.


    Run the following command to build your Docker image and tag it with your Docker Hub username and desired repository name:

docker build -t your-docker-username/auth-app:latest .


Replace your-docker-username with your Docker Hub username and auth-app with your desired repository name.


You will get a similar response like this:

[+] Building 8.4s (11/11) FINISHED                                                                                              docker:desktop-linux
 => [internal] load build definition from Dockerfile                                                                                            0.0s
 => => transferring dockerfile: 487B                                                                                                            0.0s
 => [internal] load .dockerignore                                                                                                               0.0s
 => => transferring context: 2B                                                                                                                 0.0s
 => [internal] load metadata for docker.io/library/node:16                                                                                      4.1s
 => [auth] library/node:pull token for registry-1.docker.io                                                                                     0.0s
 => [1/5] FROM docker.io/library/node:16@sha256:f77a1aef2da8d83e45ec990f45df50f1a286c5fe8bbfb8c6e4246c6389705c0b                                0.0s
 => [internal] load build context                                                                                                               0.3s
 => => transferring context: 4.55MB                                                                                                             0.3s
 => CACHED [2/5] WORKDIR /usr/src/app                                                                                                           0.0s
 => [3/5] COPY package*.json ./                                                                                                                 0.0s
 => [4/5] RUN npm install                                                                                                                       3.5s
 => [5/5] COPY . .                                                                                                                              0.2s
 => exporting to image                                                                                                                          0.1s 
 => => exporting layers                                                                                                                         0.1s 
 => => writing image sha256:23304094353243bf75417ea2db7794ddaf0c788b3695c9d2c5e9257887e113cf                                                    0.0s
 => => naming to docker.io/wise4rmgod/auth-app:latest                                                                                       1.0s
  • Log in to Docker Hub: Authenticate your Docker client with your Docker Hub account by executing the following command:
docker login


Enter your Docker Hub username and password When prompted, you will get a similar response if it is successful.

Authenticating with existing credentials...
Login Succeeded


  • Push the Docker image to Docker Hub: Once logged in, push your tagged Docker image to your Docker Hub repository using the following command:
 docker push your-docker-username/auth-app:latest

This command uploads your local image to Docker Hub under your specified repository.

Response:

6198dc681375: Pushed 
9214cb11fa0d: Pushed 
0bec55053fbf: Pushed 
dd387bc6b362: Mounted from wise4rmgod/blogpost-app 
8ae0c889ca84: Mounted from wise4rmgod/blogpost-app 
be36d2a441aa: Mounted from wise4rmgod/blogpost-app 
c91ec53bcc27: Mounted from wise4rmgod/blogpost-app 
03f6e3800bbe: Mounted from wise4rmgod/blogpost-app 
ad3b30eb29d3: Mounted from wise4rmgod/blogpost-app 
2a7587eb01b6: Mounted from wise4rmgod/blogpost-app 
a10e482288d1: Mounted from wise4rmgod/blogpost-app 
f9cfc9f6b603: Mounted from wise4rmgod/blogpost-app 
latest: digest: sha256:8cde1cdf557e8f84b435ab7d8c07780e37049351cb1220b7e4df1a193fe84027 size: 2842


Verify the Push: Go to your Docker Hub account on the web and navigate to your repository to confirm that your Docker image has been successfully pushed.


Verify the push

Deploy your project to Aptible.

This tutorial assumes you have a basic understanding of setting up an environmentapplicationendpoint, and database on the Aptible platform. The tutorial utilizes Redis as the database and employs Direct Docker for deployment.

  • Log in to Aptible via CLI using the following command:
aptible login


You will be prompted to enter your email and password. If successful, you will receive a response similar to this:

Token written to /Users/wisdomnwokocha/.aptible/tokens.json
This token will expire after 7 days (use --lifetime to customize)
  • Now, deploy your app using the following command:

Syntax:

aptible deploy --app <app name> --docker-image <docker image in cloud>


Example command:

aptible deploy --app reactgame --docker-image wise4rmgod/auth-app


You will receive a response similar to the following:

Deploying app...
INFO -- : Starting App deploy operation with ID: 62628758
INFO -- : Deploying without git repository
INFO -- : Writing .aptible.env file...
INFO -- : Fetching app image: wise4rmgod/auth-app...
INFO -- : Pulling from wise4rmgod/auth-app
INFO -- : 26ee4ff96582: Pulling fs layer
INFO -- : 446eab4103f4: Pulling fs layer
INFO -- : 2e3c22a0f840: Pulling fs layer
INFO -- : a7ab8ad9b408: Pulling fs layer
INFO -- : 3808fdf0c601: Pulling fs layer
INFO -- : ab9e4075c671: Pulling fs layer
INFO -- : 362360c8cef6: Pulling fs layer
INFO -- : 928b5d11ac66: Pulling fs layer
INFO -- : dc87e077ac61: Pulling fs layer
INFO -- : 8a5fcbf535dc: Pulling fs layer
INFO -- : 469401a1d41f: Pulling fs layer
INFO -- : eed607c017df: Pulling fs layer
INFO -- : 2e3c22a0f840: Downloading: 515 KB / 49.8 MB
INFO -- : 446eab4103f4: Downloading: 173 KB / 16.6 MB
INFO -- : 26ee4ff96582: Downloading: 495 KB / 47 MB
INFO -- : a7ab8ad9b408: Downloading: 527 KB / 175 MB
INFO -- : 2e3c22a0f840: Downloading: 25.2 MB / 49.8 MB
INFO -- : ab9e4075c671: Downloading: 352 KB / 33.4 MB
INFO -- : a7ab8ad9b408: Downloading: 35.4 MB / 175 MB
INFO -- : 26ee4ff96582: Pull complete
INFO -- : 446eab4103f4: Pull complete
INFO -- : 2e3c22a0f840: Pull complete
INFO -- : a7ab8ad9b408: Downloading: 70.8 MB / 175 MB
INFO -- : a7ab8ad9b408: Downloading: 106 MB / 175 MB
INFO -- : a7ab8ad9b408: Downloading: 140 MB / 175 MB
.
INFO -- : a7ab8ad9b408: Pull complete
INFO -- : 3808fdf0c601: Pull complete
INFO -- : ab9e4075c671: Pull complete
INFO -- : 362360c8cef6: Pull complete
INFO -- : 928b5d11ac66: Pull complete
INFO -- : dc87e077ac61: Pull complete
INFO -- : 8a5fcbf535dc: Pull complete
INFO -- : 469401a1d41f: Pull complete
INFO -- : eed607c017df: Pull complete
INFO -- : Digest: sha256:8cde1cdf557e8f84b435ab7d8c07780e37049351cb1220b7e4df1a193fe84027
INFO -- : Status: Downloaded newer image for wise4rmgod/auth-app:latest
INFO -- : No Procfile found in git directory or /.aptible/Procfile found in Docker image: using Docker image CMD
INFO -- : No .aptible.yml found in git directory or /.aptible/.aptible.yml found in Docker image: no before_release commands will run
INFO -- : Pushing image dualstack-v2-registry-i-0a7c34b9c3e849206.aptible.in:46022/app-65706/e305b9c9-c6e5-487b-a4f2-6b07306c5cd6:latest to private Docker registry...
INFO -- : The push refers to repository [dualstack-v2-registry-i-0a7c34b9c3e849206.aptible.in:46022/app-65706/e305b9c9-c6e5-487b-a4f2-6b07306c5cd6]
INFO -- : 8ae0c889ca84: Pushed
INFO -- : dd387bc6b362: Pushed
INFO -- : c91ec53bcc27: Pushing: 522 KB / 93.6 MB
INFO -- : 6198dc681375: Pushed
INFO -- : 0bec55053fbf: Pushed
INFO -- : 9214cb11fa0d: Pushed
INFO -- : 2a7587eb01b6: Pushing: 544 KB / 137 MB
INFO -- : ad3b30eb29d3: Pushing: 542 KB / 444 MB
INFO -- : c91ec53bcc27: Pushing: 31.3 MB / 93.6 MB
INFO -- : be36d2a441aa: Pushed
INFO -- : 03f6e3800bbe: Pushed
INFO -- : 2a7587eb01b6: Pushing: 34.9 MB / 137 MB
INFO -- : a10e482288d1: Pushing: 338 KB / 30.7 MB
INFO -- : f9cfc9f6b603: Pushing: 513 KB / 103 MB
INFO -- : c91ec53bcc27: Pushing: 62.7 MB / 93.6 MB
INFO -- : f9cfc9f6b603: Pushing: 35.1 MB / 103 MB
INFO -- : 2a7587eb01b6: Pushing: 69.4 MB / 137 MB
INFO -- : f9cfc9f6b603: Pushing: 69.2 MB / 103 MB
INFO -- : ad3b30eb29d3: Pushing: 45 MB / 444 MB
INFO -- : a10e482288d1: Pushed
INFO -- : 2a7587eb01b6: Pushing: 104 MB / 137 MB
INFO -- : c91ec53bcc27: Pushed
INFO -- : ad3b30eb29d3: Pushing: 90.5 MB / 444 MB
INFO -- : f9cfc9f6b603: Pushed
INFO -- : 2a7587eb01b6: Pushed
INFO -- : ad3b30eb29d3: Pushing: 135 MB / 444 MB
INFO -- : ad3b30eb29d3: Pushing: 178 MB / 444 MB
INFO -- : ad3b30eb29d3: Pushing: 223 MB / 444 MB
INFO -- : ad3b30eb29d3: Pushing: 267 MB / 444 MB
INFO -- : ad3b30eb29d3: Pushing: 311 MB / 444 MB
INFO -- : ad3b30eb29d3: Pushing: 357 MB / 444 MB
INFO -- : ad3b30eb29d3: Pushing: 401 MB / 444 MB
INFO -- : ad3b30eb29d3: Pushed
INFO -- : latest: digest: sha256:8cde1cdf557e8f84b435ab7d8c07780e37049351cb1220b7e4df1a193fe84027 size: 2842
INFO -- : Pulling from app-65706/e305b9c9-c6e5-487b-a4f2-6b07306c5cd6
INFO -- : Digest: sha256:8cde1cdf557e8f84b435ab7d8c07780e37049351cb1220b7e4df1a193fe84027
INFO -- : Status: Image is up to date for dualstack-v2-registry-i-0a7c34b9c3e849206.aptible.in:46022/app-65706/e305b9c9-c6e5-487b-a4f2-6b07306c5cd6:latest
INFO -- : Image app-65706/e305b9c9-c6e5-487b-a4f2-6b07306c5cd6 successfully pushed to registry.
INFO -- : STARTING: Register service cmd in API
INFO -- : COMPLETED (after 0.27s): Register service cmd in API
INFO -- : STARTING: Derive placement policy for service cmd
INFO -- : COMPLETED (after 0.13s): Derive placement policy for service cmd
INFO -- : STARTING: Create new release for service cmd
INFO -- : COMPLETED (after 0.25s): Create new release for service cmd
INFO -- : STARTING: Schedule service cmd
...
INFO -- : COMPLETED (after 13.5s): Schedule service cmd
INFO -- : STARTING: Stop old app containers for service cmd
INFO -- : COMPLETED (after 0.0s): Stop old app containers for service cmd
INFO -- : STARTING: Start app containers for service cmd
INFO -- : WAITING FOR: Start app containers for service cmd

INFO -- : WAITING FOR: Start app containers for service cmd
INFO -- : COMPLETED (after 18.56s): Start app containers for service cmd
INFO -- : STARTING: Delete old containers for service cmd in API
INFO -- : COMPLETED (after 0.0s): Delete old containers for service cmd in API
INFO -- : STARTING: Commit app containers in API for service cmd
INFO -- : COMPLETED (after 0.26s): Commit app containers in API for service cmd
INFO -- : STARTING: Commit service cmd in API
INFO -- : COMPLETED (after 0.13s): Commit service cmd in API
INFO -- : STARTING: Cache maintenance page
INFO -- : COMPLETED (after 0.28s): Cache maintenance page
INFO -- : STARTING: Commit app in API
INFO -- : COMPLETED (after 0.18s): Commit app in API
INFO -- : App deploy successful.


  • Visit the Aptible Dashboard to confirm that the deployment was successful.

Aptible Dashboard

  • Select the cmd Docker CMD and click the Create Endpoint button

This will allow you to expose your database to the public internet.

Deploy your code

Implement CI/CD Pipeline with Aptible Terraform

Before you proceed with this section, you must have a Terraform cloud account and Terraform CLI installed.


The Aptible Terraform provider enables you to manage your Aptible resources directly from Terraform.

This allows you to use infrastructure as code (IaC) instead of manually initiating operations from the Aptible Dashboard or Aptible CLI.

With the Aptible Terraform provider, you can automate setting up new environments, including creating, scaling, modifying, and de-provisioning apps and databases.


  • Login to Terraform via CLI

In your terminal, use the terraform login command to create an API token and configure your CLI to use it.

terraform login


  • Create a new directory: Create a new directory for your Terraform project.

This is the structure of my folders now.

Folder structure

  • Create a new file:

Create a new file in the directory you just created and name it main.tf


  • Add provider and resource information: In the main.tf file, add the provider information for the cloud service you want.

    For example, if you want to use AWS, add the following code:

resource "aptible_app" "example-app" {
    env_id = data.aptible_environment.example.env_id
    handle = "example-app"
    config = {
        "REDIS_URL": aptible_database.example-redis-db.default_connection_url,
        "DATABASE_URL": aptible_database.example-pg-db.default_connection_url,
    }
    service {
        process_type           = "cmd"
        container_count        = 1
        container_memory_limit = 1024
    }
}

resource "aptible_database" "example-redis-b" {
  env_id         = data.aptible_environment.example.env_id
  handle         = "example-redis-db"
  database_type  = "redis"
  container_size = 512
  disk_size      = 10
  version        = "5.0"
}


  • Initialize Terraform: In your terminal, navigate to the directory where you created your Terraform project and run the following command to initialize Terraform:

    terraform init
    
  • Create an execution plan: Run the following command to create an execution plan:

    terraform plan
    
  • Apply the changes: Finally, run the following command to apply the changes:

    terraform apply
    

Conclusion

Integrating Node.js, Aptible Terraform, and Redis offers a robust and efficient framework for constructing a secure and scalable authentication API gateway.