Date Created: 2024-10-29
By: 16BitMiker
[ BACK.. ]
When working in isolated environments, staging servers, or internal networks, you often need SSL/TLS—but a full certificate authority setup or a public CA like Let's Encrypt isn't always warranted. Self-signed certificates are a time-tested solution in these scenarios.
This guide walks you through an automated Bash script tailored for Debian 12 that sets up a self-signed certificate using OpenSSL. It even adds a touch of interactive Perl magic 🧙♂️ to streamline certificate detail entry.
Let’s break it down step-by-step and discuss the reasoning behind each part.
This all-in-one script performs the following tasks:
Installs OpenSSL (if not already installed)
Creates necessary directories for cert/key storage
Generates a 2048-bit private key
Prompts the user for certificate details via a Perl one-liner
Builds and signs a self-signed certificate
Sets secure file permissions
Validates the resulting certificate
Here’s the full script:
x
#
# Debian 12 Self Signed Cert Setup
# By: 16BitMiker (v2024-10-28)
set -x # Enable debug output
set -e # Exit on any error
# ~~~~~~~~~~~~~~~~ DEPENDENCIES
# Update package list and install OpenSSL silently
sudo DEBIAN_FRONTEND=noninteractive apt-get update -y
sudo DEBIAN_FRONTEND=noninteractive apt-get install openssl -y
# ~~~~~~~~~~~~~~~~ SETUP
# Create necessary directories for certificate and key
sudo mkdir -p /etc/ssl/certs /etc/ssl/private
# Generate a secure 2048-bit RSA private key
sudo openssl genrsa -out /etc/ssl/private/mykey.key 2048
# ~~~~~~~~~~~~~~~~ GENERATE CERTIFICATE
# Perl script for interactive data entry and OpenSSL command construction
perl -M'Term::ANSIColor qw(:constants)' -sE'
map
{
# Prompt user for each field
printf qq|> %s%s: |, uc( $_ ), m~COUNTRY~i ? q| (2 Letter Code)| : q||;
chomp( $choice = <STDIN> );
# Replace placeholder with user input in the OpenSSL command
$cmd =~ s~${_}~${choice}~;
} qw( COUNTRY REGION CITY COMPANY DIVSION DOMAIN EMAIL );
# Show final OpenSSL command in green before executing
say q|> |, GREEN $cmd, RESET;
system $cmd;
' -- -cmd='sudo openssl req -new -x509 -sha256 -key /etc/ssl/private/mykey.key -out /etc/ssl/certs/mycert.crt -days 365 -subj "/C=COUNTRY/ST=REGION/L=CITY/O=COMPANY/OU=DIVSION/CN=DOMAIN/emailAddress=EMAIL"'
# ~~~~~~~~~~~~~~~~ PERMISSIONS
# Secure the private key: root-only read/write
sudo chmod 600 /etc/ssl/private/mykey.key
sudo chown root:root /etc/ssl/private/mykey.key
# Make the certificate world-readable, but root-owned
sudo chmod 644 /etc/ssl/certs/mycert.crt
sudo chown root:root /etc/ssl/certs/mycert.crt
# ~~~~~~~~~~~~~~~~ VALIDATION
# Output the certificate details to confirm accuracy
sudo openssl x509 -in /etc/ssl/certs/mycert.crt -text -noout
xxxxxxxxxx
sudo DEBIAN_FRONTEND=noninteractive apt-get install openssl -y
By setting DEBIAN_FRONTEND=noninteractive
, we ensure the script can run in non-interactive environments—such as CI pipelines or automated VM provisioning—without hanging on prompts.
Instead of using repetitive read
commands in Bash, we use a short Perl script to gather user input and dynamically build the OpenSSL command.
Let’s break down what it does:
xxxxxxxxxx
map
{
printf |> %s%s: |, uc( $_ ), m~COUNTRY~i ? | (2 )| : ||;
chomp( $choice = <STDIN> );
$cmd =~ s~${_}~${choice}~;
} qw( COUNTRY REGION CITY COMPANY DIVSION DOMAIN EMAIL );
The map
function iterates through a predefined list of fields required by the certificate.
Each field is prompted with contextual hints (e.g., "(2 Letter Code)" for country).
The user’s input replaces placeholders in the OpenSSL command string ($cmd
).
Finally, the constructed command is printed with color (thanks to Term::ANSIColor
) and executed.
This makes the script more user-friendly and avoids hardcoding.
xxxxxxxxxx
sudo chmod 600 /etc/ssl/private/mykey.key
sudo chmod 644 /etc/ssl/certs/mycert.crt
The private key is readable only by root (600
). This is essential to ensure it’s not exposed to other users on the system.
The certificate itself is safe to be publicly readable (644
), but only root should be able to modify it.
These permissions align with best practices for managing TLS assets on Linux systems.
xxxxxxxxxx
sudo openssl x509 -in /etc/ssl/certs/mycert.crt -text -noout
This final step dumps the certificate details so you can visually inspect them—handy for confirming the subject fields, expiration date, and hashing algorithm used.
This script is well-suited for:
Internal development environments
Testing SSL configurations
Securing local services (e.g., internal dashboards, self-hosted tools)
Quick demonstrations or educational purposes
However, it’s important to remember:
⚠️ Self-signed certificates are not trusted by browsers or external users. They are ideal for internal or non-production use only.
Want a longer certificate lifespan? Modify -days 365
to a larger value.
Need to support SANs (Subject Alternative Names)? You’ll need to add a config file and reference it with -config
and -extensions
in the OpenSSL command.
Automating this across multiple machines? Combine it with Ansible or SSH-based scripting to deploy certs at scale.
This script demonstrates how a small amount of automation—paired with a little scripting flair—can simplify a repetitive but critical process. Whether you're spinning up test environments or teaching SSL fundamentals, having a go-to tool like this in your sysadmin kit can save time and reduce human error.
If you’re working with internal services or creating mock endpoints for testing, this setup gets you up and running in minutes.
Happy scripting, and stay secure! 🔐
[ BACK.. ]