Use different names for deploy and service users on both servers
This commit is contained in:
parent
07de8f2f6a
commit
14b6eaeffa
1 changed files with 142 additions and 127 deletions
|
@ -99,17 +99,17 @@ This setup uses a **principle of least privilege** approach with separate users
|
||||||
- **SSH Access**: Disabled after setup
|
- **SSH Access**: Disabled after setup
|
||||||
- **Privileges**: Full system access (used only during initial configuration)
|
- **Privileges**: Full system access (used only during initial configuration)
|
||||||
|
|
||||||
2. **Deployment User (`DEPLOY_USER`)**
|
2. **Deployment User (`CI_DEPLOY_USER` on CI Linode, `PROD_DEPLOY_USER` on Production Linode)**
|
||||||
- **Purpose**: SSH access, deployment tasks, system administration
|
- **Purpose**: SSH access, deployment tasks, system administration
|
||||||
- **SSH Access**: Enabled with key-based authentication
|
- **SSH Access**: Enabled with key-based authentication
|
||||||
- **Privileges**: Sudo access for deployment and administrative tasks
|
- **Privileges**: Sudo access for deployment and administrative tasks
|
||||||
- **Examples**: `deploy`, `ci`, `admin`
|
- **Example**: `ci-deploy` / `prod-deploy`
|
||||||
|
|
||||||
3. **Service Account (`SERVICE_USER`)**
|
3. **Service Account (`CI_SERVICE_USER` on CI Linode, `PROD_SERVICE_USER` on Production Linode)**
|
||||||
- **Purpose**: Running application services (Docker containers, databases)
|
- **Purpose**: Running application services (Docker containers, databases)
|
||||||
- **SSH Access**: None (no login shell)
|
- **SSH Access**: None (no login shell)
|
||||||
- **Privileges**: No sudo access, minimal system access
|
- **Privileges**: No sudo access, minimal system access
|
||||||
- **Examples**: `appuser`, `service`, `app`
|
- **Example**: `ci-service` / `prod-service`
|
||||||
|
|
||||||
### Security Benefits
|
### Security Benefits
|
||||||
|
|
||||||
|
@ -121,9 +121,9 @@ This setup uses a **principle of least privilege** approach with separate users
|
||||||
|
|
||||||
### File Permissions
|
### File Permissions
|
||||||
|
|
||||||
- **Application files**: Owned by `SERVICE_USER` for security
|
- **Application files**: Owned by `CI_SERVICE_USER` for security (CI Linode) / `PROD_SERVICE_USER` for security (Production Linode)
|
||||||
- **Docker operations**: Run by `DEPLOY_USER` with sudo (deployment only)
|
- **Docker operations**: Run by `CI_SERVICE_USER` with Docker group access (CI Linode) / `PROD_SERVICE_USER` with Docker group access (Production Linode)
|
||||||
- **Service execution**: Run by `SERVICE_USER` (no sudo needed)
|
- **Service execution**: Run by `CI_SERVICE_USER` (no sudo needed) / `PROD_SERVICE_USER` (no sudo needed)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -172,30 +172,30 @@ ssh root@YOUR_PRODUCTION_IP
|
||||||
|
|
||||||
Before proceeding, decide on:
|
Before proceeding, decide on:
|
||||||
|
|
||||||
1. **Service Account Name**: Choose a username for the service account (e.g., `appuser`, `deploy`, `service`)
|
1. **CI Service Account Name**: Choose a username for the CI service account (e.g., `ci-service`)
|
||||||
- Replace `SERVICE_USER` in this guide with your chosen name
|
- Replace `CI_SERVICE_USER` in this guide with your chosen name
|
||||||
- This account runs the actual application services
|
- This account runs the CI pipeline and Docker operations on the CI Linode
|
||||||
|
|
||||||
2. **Deployment User Name**: Choose a username for deployment tasks (e.g., `deploy`, `ci`, `admin`)
|
2. **CI Deployment User Name**: Choose a username for CI deployment tasks (e.g., `ci-deploy`)
|
||||||
- Replace `DEPLOY_USER` in this guide with your chosen name
|
- Replace `CI_DEPLOY_USER` in this guide with your chosen name
|
||||||
- This account has sudo privileges for deployment tasks
|
- This account has sudo privileges for deployment tasks
|
||||||
|
|
||||||
3. **Application Name**: Choose a name for your application (e.g., `myapp`, `webapp`, `api`)
|
3. **Application Name**: Choose a name for your application (e.g., `sharenet`)
|
||||||
- Replace `APP_NAME` in this guide with your chosen name
|
- Replace `APP_NAME` in this guide with your chosen name
|
||||||
|
|
||||||
4. **Domain Name** (Optional): If you have a domain, note it for SSL configuration
|
4. **Domain Name** (Optional): If you have a domain, note it for SSL configuration
|
||||||
- Replace `your-domain.com` in this guide with your actual domain
|
- Replace `your-domain.com` in this guide with your actual domain
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
- If you choose `appuser` as service account, `deploy` as deployment user, and `myapp` as application name:
|
- If you choose `ci-service` as CI service account, `ci-deploy` as CI deployment user, and `sharenet` as application name:
|
||||||
- Replace all `SERVICE_USER` with `appuser`
|
- Replace all `CI_SERVICE_USER` with `ci-service`
|
||||||
- Replace all `DEPLOY_USER` with `deploy`
|
- Replace all `CI_DEPLOY_USER` with `ci-deploy`
|
||||||
- Replace all `APP_NAME` with `myapp`
|
- Replace all `APP_NAME` with `sharenet`
|
||||||
- If you have a domain `example.com`, replace `your-domain.com` with `example.com`
|
- If you have a domain `example.com`, replace `your-domain.com` with `example.com`
|
||||||
|
|
||||||
**Security Model**:
|
**Security Model**:
|
||||||
- **Service Account (`SERVICE_USER`)**: Runs application services, no sudo access
|
- **CI Service Account (`CI_SERVICE_USER`)**: Runs CI pipeline and Docker operations, no sudo access
|
||||||
- **Deployment User (`DEPLOY_USER`)**: Handles deployments via SSH, has sudo access
|
- **CI Deployment User (`CI_DEPLOY_USER`)**: Handles SSH communication and orchestration, has sudo access
|
||||||
- **Root**: Only used for initial setup, then disabled for SSH access
|
- **Root**: Only used for initial setup, then disabled for SSH access
|
||||||
|
|
||||||
#### 0.4 Set Up SSH Key Authentication for Local Development
|
#### 0.4 Set Up SSH Key Authentication for Local Development
|
||||||
|
@ -257,50 +257,74 @@ ssh root@YOUR_PRODUCTION_IP 'echo "SSH key authentication works for Production"'
|
||||||
|
|
||||||
On both Linodes, create the deployment user with sudo privileges:
|
On both Linodes, create the deployment user with sudo privileges:
|
||||||
|
|
||||||
|
**For CI Linode:**
|
||||||
```bash
|
```bash
|
||||||
# Create deployment user
|
# Create CI deployment user
|
||||||
sudo useradd -m -s /bin/bash DEPLOY_USER
|
sudo useradd -m -s /bin/bash CI_DEPLOY_USER
|
||||||
sudo usermod -aG sudo DEPLOY_USER
|
sudo usermod -aG sudo CI_DEPLOY_USER
|
||||||
|
|
||||||
# Set a secure password (for emergency access only)
|
# Set a secure password (for emergency access only)
|
||||||
echo "DEPLOY_USER:$(openssl rand -base64 32)" | sudo chpasswd
|
echo "CI_DEPLOY_USER:$(openssl rand -base64 32)" | sudo chpasswd
|
||||||
|
|
||||||
# Copy your SSH key to the deployment user
|
# Copy your SSH key to the CI deployment user
|
||||||
sudo mkdir -p /home/DEPLOY_USER/.ssh
|
sudo mkdir -p /home/CI_DEPLOY_USER/.ssh
|
||||||
sudo cp ~/.ssh/authorized_keys /home/DEPLOY_USER/.ssh/
|
sudo cp ~/.ssh/authorized_keys /home/CI_DEPLOY_USER/.ssh/
|
||||||
sudo chown -R DEPLOY_USER:DEPLOY_USER /home/DEPLOY_USER/.ssh
|
sudo chown -R CI_DEPLOY_USER:CI_DEPLOY_USER /home/CI_DEPLOY_USER/.ssh
|
||||||
sudo chmod 700 /home/DEPLOY_USER/.ssh
|
sudo chmod 700 /home/CI_DEPLOY_USER/.ssh
|
||||||
sudo chmod 600 /home/DEPLOY_USER/.ssh/authorized_keys
|
sudo chmod 600 /home/CI_DEPLOY_USER/.ssh/authorized_keys
|
||||||
|
|
||||||
# Configure sudo to use SSH key authentication (most secure)
|
# Configure sudo to use SSH key authentication (most secure)
|
||||||
echo "DEPLOY_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/DEPLOY_USER
|
echo "CI_DEPLOY_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/CI_DEPLOY_USER
|
||||||
sudo chmod 440 /etc/sudoers.d/DEPLOY_USER
|
sudo chmod 440 /etc/sudoers.d/CI_DEPLOY_USER
|
||||||
```
|
```
|
||||||
|
|
||||||
**Security Note**: This configuration allows the DEPLOY_USER to use sudo without a password, which is more secure for CI/CD automation since there are no passwords to store or expose. The random password is set for emergency console access only.
|
**For Production Linode:**
|
||||||
|
```bash
|
||||||
|
# Create production deployment user
|
||||||
|
sudo useradd -m -s /bin/bash PROD_DEPLOY_USER
|
||||||
|
sudo usermod -aG sudo PROD_DEPLOY_USER
|
||||||
|
|
||||||
|
# Set a secure password (for emergency access only)
|
||||||
|
echo "PROD_DEPLOY_USER:$(openssl rand -base64 32)" | sudo chpasswd
|
||||||
|
|
||||||
|
# Copy your SSH key to the production deployment user
|
||||||
|
sudo mkdir -p /home/PROD_DEPLOY_USER/.ssh
|
||||||
|
sudo cp ~/.ssh/authorized_keys /home/PROD_DEPLOY_USER/.ssh/
|
||||||
|
sudo chown -R PROD_DEPLOY_USER:PROD_DEPLOY_USER /home/PROD_DEPLOY_USER/.ssh
|
||||||
|
sudo chmod 700 /home/PROD_DEPLOY_USER/.ssh
|
||||||
|
sudo chmod 600 /home/PROD_DEPLOY_USER/.ssh/authorized_keys
|
||||||
|
|
||||||
|
# Configure sudo to use SSH key authentication (most secure)
|
||||||
|
echo "PROD_DEPLOY_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/PROD_DEPLOY_USER
|
||||||
|
sudo chmod 440 /etc/sudoers.d/PROD_DEPLOY_USER
|
||||||
|
```
|
||||||
|
|
||||||
|
**Security Note**: This configuration allows the deployment users to use sudo without a password, which is more secure for CI/CD automation since there are no passwords to store or expose. The random password is set for emergency console access only.
|
||||||
|
|
||||||
##### 0.4.5 Test Sudo Access
|
##### 0.4.5 Test Sudo Access
|
||||||
|
|
||||||
Test that the deployment user can use sudo without password prompts:
|
Test that the deployment users can use sudo without password prompts:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Test sudo access
|
# Test CI deployment user sudo access
|
||||||
ssh DEPLOY_USER@YOUR_CI_CD_IP 'sudo whoami'
|
ssh CI_DEPLOY_USER@YOUR_CI_CD_IP 'sudo whoami'
|
||||||
ssh DEPLOY_USER@YOUR_PRODUCTION_IP 'sudo whoami'
|
|
||||||
|
# Test production deployment user sudo access
|
||||||
|
ssh PROD_DEPLOY_USER@YOUR_PRODUCTION_IP 'sudo whoami'
|
||||||
```
|
```
|
||||||
|
|
||||||
**Expected output**: Both commands should return `root` without prompting for a password.
|
**Expected output**: Both commands should return `root` without prompting for a password.
|
||||||
|
|
||||||
##### 0.4.6 Test Deployment User Access
|
##### 0.4.6 Test Deployment User Access
|
||||||
|
|
||||||
Test that you can access both servers as the deployment user:
|
Test that you can access both servers as the deployment users:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Test CI/CD Linode
|
# Test CI/CD Linode
|
||||||
ssh DEPLOY_USER@YOUR_CI_CD_IP 'echo "Deployment user SSH access works for CI/CD"'
|
ssh CI_DEPLOY_USER@YOUR_CI_CD_IP 'echo "CI deployment user SSH access works for CI/CD"'
|
||||||
|
|
||||||
# Test Production Linode
|
# Test Production Linode
|
||||||
ssh DEPLOY_USER@YOUR_PRODUCTION_IP 'echo "Deployment user SSH access works for Production"'
|
ssh PROD_DEPLOY_USER@YOUR_PRODUCTION_IP 'echo "Production deployment user SSH access works for Production"'
|
||||||
```
|
```
|
||||||
|
|
||||||
**Expected output**: The echo messages should appear without password prompts.
|
**Expected output**: The echo messages should appear without password prompts.
|
||||||
|
@ -314,13 +338,13 @@ On your local machine, create an SSH config file for easy access:
|
||||||
cat > ~/.ssh/config << 'EOF'
|
cat > ~/.ssh/config << 'EOF'
|
||||||
Host ci-cd-dev
|
Host ci-cd-dev
|
||||||
HostName YOUR_CI_CD_IP
|
HostName YOUR_CI_CD_IP
|
||||||
User DEPLOY_USER
|
User CI_DEPLOY_USER
|
||||||
IdentityFile ~/.ssh/id_ed25519
|
IdentityFile ~/.ssh/id_ed25519
|
||||||
StrictHostKeyChecking no
|
StrictHostKeyChecking no
|
||||||
|
|
||||||
Host production-dev
|
Host production-dev
|
||||||
HostName YOUR_PRODUCTION_IP
|
HostName YOUR_PRODUCTION_IP
|
||||||
User DEPLOY_USER
|
User PROD_DEPLOY_USER
|
||||||
IdentityFile ~/.ssh/id_ed25519
|
IdentityFile ~/.ssh/id_ed25519
|
||||||
StrictHostKeyChecking no
|
StrictHostKeyChecking no
|
||||||
EOF
|
EOF
|
||||||
|
@ -405,26 +429,26 @@ sudo apt install -y \
|
||||||
|
|
||||||
### Step 2: Create Users
|
### Step 2: Create Users
|
||||||
|
|
||||||
#### 2.1 Create Service Account
|
#### 2.1 Create CI Service Account
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Create dedicated group for the service account
|
# Create dedicated group for the CI service account
|
||||||
sudo groupadd -r SERVICE_USER
|
sudo groupadd -r CI_SERVICE_USER
|
||||||
|
|
||||||
# Create service account user with dedicated group
|
# Create CI service account user with dedicated group
|
||||||
sudo useradd -r -g SERVICE_USER -s /bin/bash -m -d /home/SERVICE_USER SERVICE_USER
|
sudo useradd -r -g CI_SERVICE_USER -s /bin/bash -m -d /home/CI_SERVICE_USER CI_SERVICE_USER
|
||||||
echo "SERVICE_USER:$(openssl rand -base64 32)" | sudo chpasswd
|
echo "CI_SERVICE_USER:$(openssl rand -base64 32)" | sudo chpasswd
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 2.2 Verify Users
|
#### 2.2 Verify Users
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo su - SERVICE_USER
|
sudo su - CI_SERVICE_USER
|
||||||
whoami
|
whoami
|
||||||
pwd
|
pwd
|
||||||
exit
|
exit
|
||||||
|
|
||||||
sudo su - DEPLOY_USER
|
sudo su - CI_DEPLOY_USER
|
||||||
whoami
|
whoami
|
||||||
pwd
|
pwd
|
||||||
exit
|
exit
|
||||||
|
@ -433,15 +457,15 @@ exit
|
||||||
### Step 3: Clone Repository for Registry Configuration
|
### Step 3: Clone Repository for Registry Configuration
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Switch to DEPLOY_USER (who has sudo access)
|
# Switch to CI_DEPLOY_USER (who has sudo access)
|
||||||
sudo su - DEPLOY_USER
|
sudo su - CI_DEPLOY_USER
|
||||||
|
|
||||||
# Create application directory and clone repository
|
# Create application directory and clone repository
|
||||||
sudo mkdir -p /opt/APP_NAME
|
sudo mkdir -p /opt/APP_NAME
|
||||||
sudo chown SERVICE_USER:SERVICE_USER /opt/APP_NAME
|
sudo chown CI_SERVICE_USER:CI_SERVICE_USER /opt/APP_NAME
|
||||||
cd /opt
|
cd /opt
|
||||||
sudo git clone https://your-forgejo-instance/your-username/APP_NAME.git
|
sudo git clone https://your-forgejo-instance/your-username/APP_NAME.git
|
||||||
sudo chown -R SERVICE_USER:SERVICE_USER APP_NAME/
|
sudo chown -R CI_SERVICE_USER:CI_SERVICE_USER APP_NAME/
|
||||||
|
|
||||||
# Verify the registry folder exists
|
# Verify the registry folder exists
|
||||||
ls -la /opt/APP_NAME/registry/
|
ls -la /opt/APP_NAME/registry/
|
||||||
|
@ -450,8 +474,8 @@ ls -la /opt/APP_NAME/registry/
|
||||||
**Important**: Replace `your-forgejo-instance`, `your-username`, and `APP_NAME` with your actual Forgejo instance URL, username, and application name.
|
**Important**: Replace `your-forgejo-instance`, `your-username`, and `APP_NAME` with your actual Forgejo instance URL, username, and application name.
|
||||||
|
|
||||||
**What this does**:
|
**What this does**:
|
||||||
- DEPLOY_USER creates the directory structure and clones the repository
|
- CI_DEPLOY_USER creates the directory structure and clones the repository
|
||||||
- SERVICE_USER owns all the files for security
|
- CI_SERVICE_USER owns all the files for security
|
||||||
- Registry configuration files are now available at `/opt/APP_NAME/registry/`
|
- Registry configuration files are now available at `/opt/APP_NAME/registry/`
|
||||||
|
|
||||||
### Step 4: Install Docker
|
### Step 4: Install Docker
|
||||||
|
@ -470,10 +494,10 @@ sudo apt update
|
||||||
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 4.3 Configure Docker for Service Account
|
#### 4.3 Configure Docker for CI Service Account
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo usermod -aG docker SERVICE_USER
|
sudo usermod -aG docker CI_SERVICE_USER
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 5: Set Up Harbor Container Registry
|
### Step 5: Set Up Harbor Container Registry
|
||||||
|
@ -493,8 +517,8 @@ echo "harbor:$(openssl rand -base64 32)" | sudo chpasswd
|
||||||
# Add harbor user to docker group
|
# Add harbor user to docker group
|
||||||
sudo usermod -aG docker harbor
|
sudo usermod -aG docker harbor
|
||||||
|
|
||||||
# Add DEPLOY_USER to harbor group for monitoring access
|
# Add CI_DEPLOY_USER to harbor group for monitoring access
|
||||||
sudo usermod -aG harbor DEPLOY_USER
|
sudo usermod -aG harbor CI_DEPLOY_USER
|
||||||
|
|
||||||
# Set proper permissions on /opt/harbor directory
|
# Set proper permissions on /opt/harbor directory
|
||||||
sudo chown harbor:harbor /opt/harbor
|
sudo chown harbor:harbor /opt/harbor
|
||||||
|
@ -573,8 +597,8 @@ echo "DB_PASSWORD: $DB_PASSWORD"
|
||||||
# Download and install Harbor
|
# Download and install Harbor
|
||||||
cd /opt/harbor
|
cd /opt/harbor
|
||||||
|
|
||||||
# Switch to the DEPLOY_USER
|
# Switch to the CI_DEPLOY_USER
|
||||||
sudo su - DEPLOY_USER
|
sudo su - CI_DEPLOY_USER
|
||||||
|
|
||||||
sudo wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz
|
sudo wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz
|
||||||
sudo tar -xzf harbor-offline-installer-v2.10.0.tgz
|
sudo tar -xzf harbor-offline-installer-v2.10.0.tgz
|
||||||
|
@ -594,8 +618,8 @@ sudo nano harbor.yml
|
||||||
**Note**: The default Harbor admin password is "Harbor12345" and will be changed in Step 5.6
|
**Note**: The default Harbor admin password is "Harbor12345" and will be changed in Step 5.6
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run the following as the DEPLOY_USER
|
# Run the following as the CI_DEPLOY_USER
|
||||||
sudo su - DEPLOY_USER
|
sudo su - CI_DEPLOY_USER
|
||||||
|
|
||||||
cd /opt/harbor/harbor
|
cd /opt/harbor/harbor
|
||||||
|
|
||||||
|
@ -613,7 +637,7 @@ cd /opt/harbor/harbor
|
||||||
# Run the following to patially adjust the permissions correctly for the harbor user
|
# Run the following to patially adjust the permissions correctly for the harbor user
|
||||||
./install.sh --with-trivy
|
./install.sh --with-trivy
|
||||||
|
|
||||||
# Exit harbor user shell to switch back to the DEPLOY_USER
|
# Exit harbor user shell to switch back to the CI_DEPLOY_USER
|
||||||
exit
|
exit
|
||||||
|
|
||||||
cd /opt/harbor/harbor
|
cd /opt/harbor/harbor
|
||||||
|
@ -634,7 +658,7 @@ docker compose up -d
|
||||||
docker compose ps -a
|
docker compose ps -a
|
||||||
|
|
||||||
# Verify using the Harbor API that all Harbor processes are healthy
|
# Verify using the Harbor API that all Harbor processes are healthy
|
||||||
curl -I -k https://localhost/api/v2.0/health
|
curl -k https://localhost/api/v2.0/health
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 5.5 Create Systemd Service
|
#### 5.5 Create Systemd Service
|
||||||
|
@ -682,30 +706,30 @@ sudo journalctl -u harbor.service -f
|
||||||
#### 5.7 Test Harbor Setup
|
#### 5.7 Test Harbor Setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Switch to DEPLOY_USER for testing
|
# Switch to CI_SERVICE_USER for testing (CI_SERVICE_USER runs CI pipeline and Docker operations)
|
||||||
sudo su - DEPLOY_USER
|
sudo su - CI_SERVICE_USER
|
||||||
|
|
||||||
# Test Docker login and push
|
# Test Docker login and push
|
||||||
docker login YOUR_CI_CD_IP:80 -u ci-user -p "your-secure-password"
|
echo "your-secure-password" | docker login YOUR_CI_CD_IP -u ci-user --password-stdin
|
||||||
|
|
||||||
# Create and push test image
|
# Create and push test image
|
||||||
echo "FROM alpine:latest" > /tmp/test.Dockerfile
|
echo "FROM alpine:latest" > /tmp/test.Dockerfile
|
||||||
docker build -f /tmp/test.Dockerfile -t YOUR_CI_CD_IP:80/APP_NAME/test:latest /tmp
|
docker build -f /tmp/test.Dockerfile -t YOUR_CI_CD_IP/APP_NAME/test:latest /tmp
|
||||||
docker push YOUR_CI_CD_IP:80/APP_NAME/test:latest
|
docker push YOUR_CI_CD_IP/APP_NAME/test:latest
|
||||||
|
|
||||||
# Test public pull (no authentication)
|
# Test public pull (no authentication)
|
||||||
docker logout YOUR_CI_CD_IP:80
|
docker logout YOUR_CI_CD_IP
|
||||||
docker pull YOUR_CI_CD_IP:80/APP_NAME/test:latest
|
docker pull YOUR_CI_CD_IP/APP_NAME/test:latest
|
||||||
|
|
||||||
# Test that unauthorized push is blocked
|
# Test that unauthorized push is blocked
|
||||||
echo "FROM alpine:latest" > /tmp/unauthorized.Dockerfile
|
echo "FROM alpine:latest" > /tmp/unauthorized.Dockerfile
|
||||||
docker build -f /tmp/unauthorized.Dockerfile -t YOUR_CI_CD_IP:80/APP_NAME/unauthorized:latest /tmp
|
docker build -f /tmp/unauthorized.Dockerfile -t YOUR_CI_CD_IP/APP_NAME/unauthorized:latest /tmp
|
||||||
docker push YOUR_CI_CD_IP:80/APP_NAME/unauthorized:latest
|
docker push YOUR_CI_CD_IP/APP_NAME/unauthorized:latest
|
||||||
# Expected: This should fail with authentication error
|
# Expected: This should fail with authentication error
|
||||||
|
|
||||||
# Clean up
|
# Clean up
|
||||||
docker rmi YOUR_CI_CD_IP:80/APP_NAME/test:latest
|
docker rmi YOUR_CI_CD_IP/APP_NAME/test:latest
|
||||||
docker rmi YOUR_CI_CD_IP:80/APP_NAME/unauthorized:latest
|
docker rmi YOUR_CI_CD_IP/APP_NAME/unauthorized:latest
|
||||||
exit
|
exit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -715,33 +739,24 @@ exit
|
||||||
- ✅ Unauthorized push is blocked
|
- ✅ Unauthorized push is blocked
|
||||||
- ✅ Web UI accessible at `https://YOUR_CI_CD_IP`
|
- ✅ Web UI accessible at `https://YOUR_CI_CD_IP`
|
||||||
|
|
||||||
|
|
||||||
cat /etc/docker/daemon.json
|
|
||||||
|
|
||||||
# 2. Check if certificate is in system CA store
|
|
||||||
ls -la /usr/local/share/ca-certificates/registry.crt
|
|
||||||
|
|
||||||
# 3. Update CA certificates and restart Docker
|
|
||||||
sudo update-ca-certificates
|
|
||||||
sudo systemctl restart docker
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 6: Set Up SSH for Production Communication
|
### Step 6: Set Up SSH for Production Communication
|
||||||
|
|
||||||
#### 6.1 Generate SSH Key Pair
|
#### 6.1 Generate SSH Key Pair
|
||||||
|
|
||||||
**Important**: Run this command as the **DEPLOY_USER** (not root or SERVICE_USER). The DEPLOY_USER is responsible for deployment orchestration and SSH communication with the production server.
|
**Important**: Run this command as the **CI_SERVICE_USER** (not root or CI_DEPLOY_USER). The CI_SERVICE_USER runs the CI pipeline and needs to SSH to the production server for automated deployments.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh-keygen -t ed25519 -C "ci-cd-server" -f ~/.ssh/id_ed25519 -N ""
|
ssh-keygen -t ed25519 -C "CI_SERVICE_USER" -f ~/.ssh/id_ed25519 -N ""
|
||||||
```
|
```
|
||||||
|
|
||||||
**What this does**:
|
**What this does**:
|
||||||
- Creates an SSH key pair for secure communication between CI/CD and production servers
|
- Creates an SSH key pair for secure communication between CI/CD and production servers
|
||||||
- The DEPLOY_USER uses this key to SSH to the production server for deployments
|
- The CI_SERVICE_USER uses this key to SSH to the production server for automated deployments
|
||||||
- The key is stored in the DEPLOY_USER's home directory for security
|
- The key is stored in the CI_SERVICE_USER's home directory for security
|
||||||
|
|
||||||
**Security Note**: The DEPLOY_USER handles deployment orchestration, while the SERVICE_USER runs the actual CI pipeline. This separation provides better security through the principle of least privilege.
|
**Security Note**: The CI_SERVICE_USER runs the CI pipeline and performs deployments, so it needs direct SSH access to the production server. This provides a clean, direct execution path without user switching.
|
||||||
|
|
||||||
|
**Deployment Flow**: When the CI pipeline completes successfully, the CI_SERVICE_USER will automatically SSH to the production server (using this key) to pull the latest images from Harbor and deploy the application stack.
|
||||||
|
|
||||||
#### 6.2 Create SSH Config
|
#### 6.2 Create SSH Config
|
||||||
|
|
||||||
|
@ -749,7 +764,7 @@ ssh-keygen -t ed25519 -C "ci-cd-server" -f ~/.ssh/id_ed25519 -N ""
|
||||||
cat > ~/.ssh/config << 'EOF'
|
cat > ~/.ssh/config << 'EOF'
|
||||||
Host production
|
Host production
|
||||||
HostName YOUR_PRODUCTION_IP
|
HostName YOUR_PRODUCTION_IP
|
||||||
User DEPLOY_USER
|
User PROD_SERVICE_USER
|
||||||
IdentityFile ~/.ssh/id_ed25519
|
IdentityFile ~/.ssh/id_ed25519
|
||||||
StrictHostKeyChecking no
|
StrictHostKeyChecking no
|
||||||
UserKnownHostsFile /dev/null
|
UserKnownHostsFile /dev/null
|
||||||
|
@ -762,7 +777,7 @@ chmod 600 ~/.ssh/config
|
||||||
|
|
||||||
#### 7.1 Download Runner
|
#### 7.1 Download Runner
|
||||||
|
|
||||||
**Important**: Run this step as the **DEPLOY_USER** (not root or SERVICE_USER). The DEPLOY_USER handles deployment tasks including downloading and installing the Forgejo runner.
|
**Important**: Run this step as the **CI_DEPLOY_USER** (not root or CI_SERVICE_USER). The CI_DEPLOY_USER handles deployment tasks including downloading and installing the Forgejo runner.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~
|
cd ~
|
||||||
|
@ -880,8 +895,8 @@ To add an existing user as an Administrator of an existing repository in Forgejo
|
||||||
**Step 3: Register the Runner**
|
**Step 3: Register the Runner**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Switch to DEPLOY_USER to register the runner
|
# Switch to CI_DEPLOY_USER to register the runner
|
||||||
sudo su - DEPLOY_USER
|
sudo su - CI_DEPLOY_USER
|
||||||
|
|
||||||
cd ~
|
cd ~
|
||||||
|
|
||||||
|
@ -899,7 +914,7 @@ forgejo-runner register \
|
||||||
**Note**: The `your-forgejo-instance` should be the **base URL** of your Forgejo instance (e.g., `https://git.<your-domain>/`), not the full path to the repository. The runner registration process will handle connecting to the specific repository based on the token you provide.
|
**Note**: The `your-forgejo-instance` should be the **base URL** of your Forgejo instance (e.g., `https://git.<your-domain>/`), not the full path to the repository. The runner registration process will handle connecting to the specific repository based on the token you provide.
|
||||||
|
|
||||||
**What this does**:
|
**What this does**:
|
||||||
- Creates the required `.runner` configuration file in the DEPLOY_USER's home directory
|
- Creates the required `.runner` configuration file in the CI_DEPLOY_USER's home directory
|
||||||
- Registers the runner with your Forgejo instance
|
- Registers the runner with your Forgejo instance
|
||||||
- Sets up the runner with appropriate labels for Ubuntu and Docker environments
|
- Sets up the runner with appropriate labels for Ubuntu and Docker environments
|
||||||
|
|
||||||
|
@ -910,10 +925,10 @@ forgejo-runner register \
|
||||||
sudo mkdir -p /etc/forgejo-runner
|
sudo mkdir -p /etc/forgejo-runner
|
||||||
|
|
||||||
# Copy the runner configuration to system location
|
# Copy the runner configuration to system location
|
||||||
sudo cp /home/DEPLOY_USER/.runner /etc/forgejo-runner/.runner
|
sudo cp /home/CI_DEPLOY_USER/.runner /etc/forgejo-runner/.runner
|
||||||
|
|
||||||
# Set proper ownership and permissions
|
# Set proper ownership and permissions
|
||||||
sudo chown SERVICE_USER:SERVICE_USER /etc/forgejo-runner/.runner
|
sudo chown CI_SERVICE_USER:CI_SERVICE_USER /etc/forgejo-runner/.runner
|
||||||
sudo chmod 600 /etc/forgejo-runner/.runner
|
sudo chmod 600 /etc/forgejo-runner/.runner
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -921,7 +936,7 @@ sudo chmod 600 /etc/forgejo-runner/.runner
|
||||||
|
|
||||||
**What this does**:
|
**What this does**:
|
||||||
- Copies the configuration to the system location (`/etc/forgejo-runner/.runner`)
|
- Copies the configuration to the system location (`/etc/forgejo-runner/.runner`)
|
||||||
- Sets proper ownership and permissions for SERVICE_USER to access the config
|
- Sets proper ownership and permissions for CI_SERVICE_USER to access the config
|
||||||
- Registers the runner with your Forgejo instance
|
- Registers the runner with your Forgejo instance
|
||||||
- Sets up the runner with appropriate labels for Ubuntu and Docker environments
|
- Sets up the runner with appropriate labels for Ubuntu and Docker environments
|
||||||
|
|
||||||
|
@ -935,7 +950,7 @@ After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=SERVICE_USER
|
User=CI_SERVICE_USER
|
||||||
WorkingDirectory=/etc/forgejo-runner
|
WorkingDirectory=/etc/forgejo-runner
|
||||||
ExecStart=/usr/bin/forgejo-runner daemon
|
ExecStart=/usr/bin/forgejo-runner daemon
|
||||||
Restart=always
|
Restart=always
|
||||||
|
@ -1005,8 +1020,8 @@ sudo journalctl -u forgejo-runner.service -f --no-pager
|
||||||
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Switch to DEPLOY_USER (who has sudo access for Docker operations)
|
# Switch to CI_DEPLOY_USER (who has sudo access for Docker operations)
|
||||||
sudo su - DEPLOY_USER
|
sudo su - CI_DEPLOY_USER
|
||||||
|
|
||||||
# Navigate to the application directory
|
# Navigate to the application directory
|
||||||
cd /opt/APP_NAME
|
cd /opt/APP_NAME
|
||||||
|
@ -1030,7 +1045,7 @@ sudo docker exec ci-dind docker version
|
||||||
- **Health checks**: Ensures DinD is fully ready before proceeding
|
- **Health checks**: Ensures DinD is fully ready before proceeding
|
||||||
- **Simple setup**: Direct Docker commands for maximum flexibility
|
- **Simple setup**: Direct Docker commands for maximum flexibility
|
||||||
|
|
||||||
**Why DEPLOY_USER**: The DEPLOY_USER handles deployment orchestration and has sudo access for Docker operations, following the principle of least privilege.
|
**Why CI_DEPLOY_USER**: The CI_DEPLOY_USER handles deployment orchestration and has sudo access for Docker operations, following the principle of least privilege.
|
||||||
|
|
||||||
#### 8.2 Configure DinD for Harbor Registry
|
#### 8.2 Configure DinD for Harbor Registry
|
||||||
|
|
||||||
|
@ -1281,35 +1296,35 @@ sudo apt install -y \
|
||||||
|
|
||||||
### Step 12: Create Users
|
### Step 12: Create Users
|
||||||
|
|
||||||
#### 12.1 Create the SERVICE_USER User
|
#### 12.1 Create the PROD_SERVICE_USER User
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Create dedicated group for the service account
|
# Create dedicated group for the production service account
|
||||||
sudo groupadd -r SERVICE_USER
|
sudo groupadd -r PROD_SERVICE_USER
|
||||||
|
|
||||||
# Create service account user with dedicated group
|
# Create production service account user with dedicated group
|
||||||
sudo useradd -r -g SERVICE_USER -s /bin/bash -m -d /home/SERVICE_USER SERVICE_USER
|
sudo useradd -r -g PROD_SERVICE_USER -s /bin/bash -m -d /home/PROD_SERVICE_USER PROD_SERVICE_USER
|
||||||
echo "SERVICE_USER:$(openssl rand -base64 32)" | sudo chpasswd
|
echo "PROD_SERVICE_USER:$(openssl rand -base64 32)" | sudo chpasswd
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 12.2 Create the DEPLOY_USER User
|
#### 12.2 Create the PROD_DEPLOY_USER User
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Create deployment user
|
# Create production deployment user
|
||||||
sudo useradd -m -s /bin/bash DEPLOY_USER
|
sudo useradd -m -s /bin/bash PROD_DEPLOY_USER
|
||||||
sudo usermod -aG sudo DEPLOY_USER
|
sudo usermod -aG sudo PROD_DEPLOY_USER
|
||||||
echo "DEPLOY_USER:$(openssl rand -base64 32)" | sudo chpasswd
|
echo "PROD_DEPLOY_USER:$(openssl rand -base64 32)" | sudo chpasswd
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 12.3 Verify Users
|
#### 12.3 Verify Users
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo su - SERVICE_USER
|
sudo su - PROD_SERVICE_USER
|
||||||
whoami
|
whoami
|
||||||
pwd
|
pwd
|
||||||
exit
|
exit
|
||||||
|
|
||||||
sudo su - DEPLOY_USER
|
sudo su - PROD_DEPLOY_USER
|
||||||
whoami
|
whoami
|
||||||
pwd
|
pwd
|
||||||
exit
|
exit
|
||||||
|
@ -1331,10 +1346,10 @@ sudo apt update
|
||||||
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 13.3 Configure Docker for Service Account
|
#### 13.3 Configure Docker for Production Service Account
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo usermod -aG docker SERVICE_USER
|
sudo usermod -aG docker PROD_SERVICE_USER
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 14: Install Docker Compose
|
### Step 14: Install Docker Compose
|
||||||
|
@ -1372,7 +1387,7 @@ sudo systemctl start fail2ban
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo mkdir -p /opt/APP_NAME
|
sudo mkdir -p /opt/APP_NAME
|
||||||
sudo chown SERVICE_USER:SERVICE_USER /opt/APP_NAME
|
sudo chown PROD_SERVICE_USER:PROD_SERVICE_USER /opt/APP_NAME
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: Replace `APP_NAME` with your actual application name. This directory name can be controlled via the `APP_NAME` secret in your Forgejo repository settings. If you set the `APP_NAME` secret to `myapp`, the deployment directory will be `/opt/myapp`.
|
**Note**: Replace `APP_NAME` with your actual application name. This directory name can be controlled via the `APP_NAME` secret in your Forgejo repository settings. If you set the `APP_NAME` secret to `myapp`, the deployment directory will be `/opt/myapp`.
|
||||||
|
@ -1381,15 +1396,15 @@ sudo chown SERVICE_USER:SERVICE_USER /opt/APP_NAME
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo mkdir -p /opt/APP_NAME/nginx/ssl
|
sudo mkdir -p /opt/APP_NAME/nginx/ssl
|
||||||
sudo chown SERVICE_USER:SERVICE_USER /opt/APP_NAME/nginx/ssl
|
sudo chown PROD_SERVICE_USER:PROD_SERVICE_USER /opt/APP_NAME/nginx/ssl
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 17: Clone Repository and Set Up Application Files
|
### Step 17: Clone Repository and Set Up Application Files
|
||||||
|
|
||||||
#### 17.1 Switch to SERVICE_USER User
|
#### 17.1 Switch to PROD_SERVICE_USER User
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo su - SERVICE_USER
|
sudo su - PROD_SERVICE_USER
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 17.2 Clone Repository
|
#### 17.2 Clone Repository
|
||||||
|
@ -1453,7 +1468,7 @@ sudo systemctl restart docker
|
||||||
#### 18.1 Add CI/CD Public Key
|
#### 18.1 Add CI/CD Public Key
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Create .ssh directory for SERVICE_USER
|
# Create .ssh directory for PROD_SERVICE_USER
|
||||||
mkdir -p ~/.ssh
|
mkdir -p ~/.ssh
|
||||||
chmod 700 ~/.ssh
|
chmod 700 ~/.ssh
|
||||||
|
|
||||||
|
@ -1669,9 +1684,9 @@ Go to your Forgejo repository and add these secrets in **Settings → Secrets an
|
||||||
**Required Secrets:**
|
**Required Secrets:**
|
||||||
- `CI_HOST`: Your CI/CD Linode IP address (used for Harbor registry access)
|
- `CI_HOST`: Your CI/CD Linode IP address (used for Harbor registry access)
|
||||||
- `PRODUCTION_IP`: Your Production Linode IP address
|
- `PRODUCTION_IP`: Your Production Linode IP address
|
||||||
- `DEPLOY_USER`: The deployment user name (e.g., `deploy`, `ci`, `admin`)
|
- `PROD_DEPLOY_USER`: The production deployment user name (e.g., `prod-deploy`)
|
||||||
- `SERVICE_USER`: The service user name (e.g., `appuser`, `service`, `app`)
|
- `PROD_SERVICE_USER`: The production service user name (e.g., `prod-service`)
|
||||||
- `APP_NAME`: Your application name (e.g., `sharenet`, `myapp`)
|
- `APP_NAME`: Your application name (e.g., `sharenet`)
|
||||||
- `POSTGRES_PASSWORD`: A strong password for the PostgreSQL database
|
- `POSTGRES_PASSWORD`: A strong password for the PostgreSQL database
|
||||||
- `HARBOR_CI_USER`: Harbor username for CI operations (e.g., `ci-user`)
|
- `HARBOR_CI_USER`: Harbor username for CI operations (e.g., `ci-user`)
|
||||||
- `HARBOR_CI_PASSWORD`: Harbor password for CI operations (the password you set for ci-user)
|
- `HARBOR_CI_PASSWORD`: Harbor password for CI operations (the password you set for ci-user)
|
||||||
|
|
Loading…
Add table
Reference in a new issue