Configuring Secure Users for OCI Ubuntu Instances

Posted on August 10, 2025

Category: Technology

Tags: Oracle Cloud, Ubuntu, SSH, Flask, web server security, user management

Views: 526

Configuring Secure Users for OCI Ubuntu Instances

I recently explored setting up a secure compute instance in Oracle Cloud Infrastructure (OCI) using Ubuntu, focusing on user management and securing a Flask web service. With Grok 3's guidance, I got clear answers to my questions about the default ubuntu user, creating additional SSH-enabled users, and the risks of running a web server as ubuntu. Here's a conversational summary of what I learned, including how to run a Flask web service as the www-data user using a TCP port.

Default User Setup in OCI Ubuntu Instances

I started by asking, "When creating a computing instance in Oracle's Cloud infrastructure, is it usual to create a user who defaults to Ubuntu and has sudo privileges without a password when connecting to the server via SSH?" Grok 3 explained that this is standard for Ubuntu-based OCI instances. When you launch an Ubuntu instance, it creates a default ubuntu user configured for SSH access with a key pair you provide during setup. This user has passwordless sudo privileges, defined in /etc/sudoers with %ubuntu ALL=(ALL) NOPASSWD: ALL. SSH access uses keys, with password authentication disabled by default (PasswordAuthentication no in /etc/ssh/sshd_config). This setup is common across cloud providers like AWS and Azure, prioritizing security through SSH keys over passwords.

Adding a New SSH-Enabled User

Next, I asked, "Can you let me know how to create an additional SSH-enabled user?" Grok 3 provided a detailed guide to create a new user, say newuser, with SSH key-based access and optional sudo privileges. Here's the process:

  1. Log in as the ubuntu user via SSH:

    ssh -i <your_private_key> ubuntu@<instance_public_ip>
    

    This gets you into the instance to start configuring the new user.

  2. Create the new user:

    sudo adduser --disabled-password --gecos "" newuser
    

    The --disabled-password flag ensures no password is set, and --gecos "" skips user info prompts.

  3. Grant sudo privileges (if needed) by adding the user to the sudo group:

    sudo usermod -aG sudo newuser
    

    This allows the new user to run administrative commands.

  4. For passwordless sudo, edit /etc/sudoers with sudo visudo and add:

    newuser ALL=(ALL) NOPASSWD: ALL
    

    This mirrors the default ubuntu user’s sudo setup.

  5. Set up SSH key-based authentication:

    • Generate an SSH key pair on your local computer:

      ssh-keygen -t rsa -b 4096 -f ~/.ssh/newuser_key
      

      This creates newuser_key (private key) and newuser_key.pub (public key). Press Enter to accept defaults or specify a passphrase for extra security. - Copy the public key to the instance (e.g., using scp):

      scp -i <your_private_key> ~/.ssh/newuser_key.pub ubuntu@<instance_public_ip>:/tmp
      

      This transfers the public key to a temporary location on the instance. - On the instance, set up the SSH directory and authorized_keys:

      sudo mkdir -p /home/newuser/.ssh
      sudo cp /tmp/newuser_key.pub /home/newuser/.ssh/authorized_keys
      sudo rm /tmp/newuser_key.pub
      

      These commands create the SSH directory, add the public key, and clean up. - Set correct permissions:

      sudo chown -R newuser:newuser /home/newuser/.ssh
      sudo chmod 700 /home/newuser/.ssh
      sudo chmod 600 /home/newuser/.ssh/authorized_keys
      

      Proper permissions ensure secure SSH access.

  6. Test SSH access with the new user’s private key:

    ssh -i ~/.ssh/newuser_key newuser@<instance_public_ip>
    

    This verifies that the new user can log in securely.

Grok 3 also suggested locking the ubuntu user after setting up the new user for better security, which I found to be a solid recommendation.

Risks of Running a Web Server as the ubuntu User

I then asked, "Does running a web server with the default user 'ubuntu' pose a significant security risk?" Grok 3 outlined the risks: - The ubuntu user is a well-known default, making it a target for attackers. - Its passwordless sudo privileges mean a compromised web server could lead to full system control. - SSH access via the ubuntu user’s key pair increases the attack surface if keys are mismanaged.

The risk depends on the setup—public-facing servers with vulnerabilities are more exposed—but using ubuntu violates the principle of least privilege. Grok 3 recommended running the web server as a non-privileged user like www-data, especially for a Flask web service.

Running a Flask Web Service as the www-data User with a TCP Port

To address the security concerns, I explored how to run a Flask web service managed by the www-data user, using a TCP port (e.g., 127.0.0.1:8000) for communication between Gunicorn and Nginx. Grok 3 provided the following steps:

  1. Create a non-privileged user:

    • Create a system user www-data (often pre-installed on Ubuntu):
      sudo adduser --system --group --no-create-home www-data
      

    This user is designed for running web services without a home directory or login shell.

  2. Set up the Flask application:

    • Create a directory for the Flask app:

      sudo mkdir -p /var/www/flask_app
      sudo chown www-data:www-data /var/www/flask_app
      sudo chmod 750 /var/www/flask_app
      

      This sets up a secure directory for the application. - Place your Flask app (e.g., app.py) in /var/www/flask_app:

      from flask import Flask
      app = Flask(__name__)
      
      @app.route('/')
      def hello():
          return 'Hello, World!'
      
      if __name__ == '__main__':
          app.run()
      

      This is a basic Flask app for testing.

  3. Install and configure Gunicorn:

    • Install Gunicorn and Flask:

      sudo apt update
      sudo apt install python3-pip
      sudo -u www-dat bash
      cd /var/www/flask_app
      python3 -m venv
      source venv/bin/activate
      pip3 install Flask gunicorn
      

      Gunicorn will serve the Flask app. - Run Gunicorn as www-data, binding to a TCP port:

      /var/www/flask_app/venv/bin/gunicorn --bind 127.0.0.1:8000 -w 4 app:app -D --chdir /var/www/flask_app
      

      The TCP port ensures local communication between Gunicorn and Nginx.

  4. Configure Nginx as a reverse proxy:

    • Install Nginx:

      sudo apt install nginx
      

      Nginx will handle incoming HTTP requests. - Configure Nginx to run as www-data by editing /etc/nginx/nginx.conf:

      user www-data;
      

      This ensures Nginx runs with minimal privileges. - Create a site configuration in /etc/nginx/sites-available/flask_app:

      server {
          listen 80;
          server_name your_domain.com;
      
          location / {
              proxy_pass http://127.0.0.1:8000;
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          }
      }
      

      This proxies requests to the Gunicorn port. - Enable the site and restart Nginx:

      sudo ln -s /etc/nginx/sites-available/flask_app /etc/nginx/sites-enabled/
      sudo nginx -t
      sudo systemctl restart nginx
      

      This activates the configuration and restarts Nginx.

  5. Set up Systemd for Gunicorn:

    • Create a systemd service file at /etc/systemd/system/flask_app.service:

      [Unit]
      Description=Gunicorn instance for Flask app
      After=network.target
      
      [Service]
      User=www-data
      Group=www-data
      WorkingDirectory=/var/www/flask_app
      Environment="PATH=/var/www/flask_app/venv/bin"
      UMask=027
      ExecStart=/var/www/flask_app/venv/bin/gunicorn --bind 127.0.0.1:8000 -w 4 app:app
      Restart=always
      
      [Install]
      WantedBy=multi-user.target
      

      This ensures Gunicorn runs persistently. - Enable and start the service:

      sudo systemctl enable flask_app
      sudo systemctl start flask_app
      

      This integrates Gunicorn with system startup.

  6. Secure file permissions:

    • Ensure the Flask app directory is owned by www-data:

      sudo chown -R www-data:www-data /var/www/flask_app
      sudo chmod -R 750 /var/www/flask_app
      

      This restricts access to the www-data user and group.

  7. Harden the setup:

    • Configure a firewall (e.g., ufw) to allow only HTTP/HTTPS traffic:

      sudo ufw allow 80/tcp
      sudo ufw allow 443/tcp
      sudo ufw enable
      

      This limits network exposure. - Lock down SSH by ensuring key-based authentication and restricting access to specific IPs if possible.

      SSH hardening reduces the risk of unauthorized access.

Key Takeaways

This conversation clarified how to manage users and secure a Flask web service in OCI Ubuntu instances. The default ubuntu user is convenient but risky for web services due to its sudo privileges and SSH access. Creating a dedicated www-data user for Flask (via Gunicorn and Nginx) with a TCP port and setting proper permissions ensures a secure setup. Additional measures like firewall rules and SSH hardening make the system robust for production use.

References

Disclaimer: This blog post was created with assistance from Grok 3, an AI developed by xAI, under my direct supervision and guidance to ensure accuracy and alignment with my vision for the content.