diff --git a/.travis.yml b/.travis.yml index a117c8f..9ee43d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: generic sudo: required matrix: include: - - dist: trusty + - dist: xenial sudo: required # Use https (public access) instead of git for git-submodules. This modifies only Travis-CI behavior git: @@ -13,4 +13,4 @@ before_install: - git submodule update --init --recursive script: - bash -c 'shopt -s globstar; shellcheck ./*.sh; shellcheck ./tests/*.sh' - - bash tests/unit-tests.sh -skip \ No newline at end of file + - bash tests/unit-tests.sh -s \ No newline at end of file diff --git a/README.md b/README.md index e001fec..29ad207 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [](https://travis-ci.org/jasonheecs/ubuntu-server-setup) This is a setup script to automate the setup and provisioning of Ubuntu servers. It does the following: -* Adds a new user account with sudo access +* Adds or updates a user account with sudo access * Adds a public ssh key for the new user account * Disables password authentication to the server * Deny root login to the server @@ -31,19 +31,19 @@ bash setup.sh ``` # Setup prompts -When the setup script is run, you will be prompted to enter the username and password of the new user account. +When the setup script is run, you will be prompted to enter the username of the new user account. Following that, you will then be prompted to add a public ssh key (which should be from your local machine) for the new account. To generate an ssh key from your local machine: ```bash -ssh-keygen -t rsa -cat ~/.ssh/id_rsa.pub +ssh-keygen -t ed25519 -a 200 -C "user@server" -f ~/.ssh/user_server_ed25519 +cat ~/.ssh/user_server_ed25519.pub ``` Finally, you will be prompted to specify a [timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for the server. It will be set to 'Asia/Singapore' if you do not specify a value. # Supported versions -This setup script has been tested against Ubuntu 14.04, Ubuntu 16.04 and Ubuntu 18.04. +This setup script has been tested against Ubuntu 14.04, Ubuntu 16.04, Ubuntu 18.04, Ubuntu 20.04 and Ubuntu 22.04. # Running tests Tests are run against a set of Vagrant VMs. To run the tests, run the following in the project's directory: -`./tests/tests.sh` \ No newline at end of file +`./tests/tests.sh` diff --git a/setup.sh b/setup.sh index 84af15c..9dc67d1 100644 --- a/setup.sh +++ b/setup.sh @@ -18,20 +18,29 @@ includeDependencies output_file="output.log" function main() { - read -rp "Enter the username of the new user account:" username - - promptForPassword + read -rp "Do you want to create a new non-root user? (Recommended) [Y/N] " createUser # Run setup functions trap cleanup EXIT SIGHUP SIGINT SIGTERM - addUserAccount "${username}" "${password}" + if [[ $createUser == [nN] ]]; then + username=$(whoami) + updateUserAccount "${username}" + elif [[ $createUser == [yY] ]]; then + read -rp "Enter the username of the new user account: " username + addUserAccount "${username}" + else + echo 'This is not a valid choice!' + exit 1 + fi read -rp $'Paste in the public SSH key for the new user:\n' sshKey echo 'Running setup script...' logTimestamp "${output_file}" exec 3>&1 >>"${output_file}" 2>&1 + + disableSudoPassword "${username}" addSSHKey "${username}" "${sshKey}" changeSSHConfig @@ -43,7 +52,7 @@ function main() { setupTimezone - echo "Installing Network Time Protocol... " >&3 + echo "Configuring System Time... " >&3 configureNTP sudo service ssh restart @@ -89,21 +98,4 @@ function setupTimezone() { echo "Timezone is set to $(cat /etc/timezone)" >&3 } -# Keep prompting for the password and password confirmation -function promptForPassword() { - PASSWORDS_MATCH=0 - while [ "${PASSWORDS_MATCH}" -eq "0" ]; do - read -s -rp "Enter new UNIX password:" password - printf "\n" - read -s -rp "Retype new UNIX password:" password_confirmation - printf "\n" - - if [[ "${password}" != "${password_confirmation}" ]]; then - echo "Passwords do not match! Please try again." - else - PASSWORDS_MATCH=1 - fi - done -} - -main \ No newline at end of file +main diff --git a/setupLibrary.sh b/setupLibrary.sh index 4df0304..455d9a4 100644 --- a/setupLibrary.sh +++ b/setupLibrary.sh @@ -1,14 +1,22 @@ #!/bin/bash +# Update the user account +# Arguments: +# Account Username +function updateUserAccount() { + local username=${1} + + sudo passwd -d "${username}" + sudo usermod -aG sudo "${username}" +} + # Add the new user account # Arguments: # Account Username -# Account Password # Flag to determine if user account is added silently. (With / Without GECOS prompt) function addUserAccount() { local username=${1} - local password=${2} - local silent_mode=${3} + local silent_mode=${2} if [[ ${silent_mode} == "true" ]]; then sudo adduser --disabled-password --gecos '' "${username}" @@ -16,8 +24,8 @@ function addUserAccount() { sudo adduser --disabled-password "${username}" fi - echo "${username}:${password}" | sudo chpasswd sudo usermod -aG sudo "${username}" + sudo passwd -d "${username}" } # Add the local machine public SSH Key for the new user account @@ -53,6 +61,7 @@ function changeSSHConfig() { # Setup the Uncomplicated Firewall function setupUfw() { + sudo apt-get install ufw sudo ufw allow OpenSSH yes y | sudo ufw enable } @@ -114,8 +123,19 @@ function setTimezone() { # Configure Network Time Protocol function configureNTP() { - sudo apt-get update - sudo apt-get --assume-yes install ntp + ubuntu_version="$(lsb_release -sr)" + + if [[ $(bc -l <<< "${ubuntu_version} >= 20.04") -eq 1 ]]; then + sudo systemctl restart systemd-timesyncd + else + sudo apt-get update + sudo apt-get --assume-yes install ntp + + # force NTP to sync + sudo service ntp stop + sudo ntpd -gq + sudo service ntp start + fi } # Gets the amount of physical memory in GB (rounded up) installed on the machine @@ -144,4 +164,4 @@ function disableSudoPassword() { function revertSudoers() { sudo cp /etc/sudoers.bak /etc/sudoers sudo rm -rf /etc/sudoers.bak -} \ No newline at end of file +} diff --git a/tests/Vagrant/Vagrantfile.focal64 b/tests/Vagrant/Vagrantfile.focal64 new file mode 100644 index 0000000..52d19a9 --- /dev/null +++ b/tests/Vagrant/Vagrantfile.focal64 @@ -0,0 +1,71 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# All Vagrant configuration is done below. The "2" in Vagrant.configure +# configures the configuration version (we support older styles for +# backwards compatibility). Please don't change it unless you know what +# you're doing. +Vagrant.configure("2") do |config| + # The most common configuration options are documented and commented below. + # For a complete reference, please see the online documentation at + # https://docs.vagrantup.com. + + # Every Vagrant development environment requires a box. You can search for + # boxes at https://atlas.hashicorp.com/search. + config.vm.box = "ubuntu/focal64" + + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + # config.vm.box_check_update = false + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + # config.vm.network "forwarded_port", guest: 80, host: 8080 + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: "192.168.33.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + # config.vm.network "public_network" + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + # config.vm.synced_folder "../data", "/vagrant_data" + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + # Example for VirtualBox: + # + # config.vm.provider "virtualbox" do |vb| + # # Display the VirtualBox GUI when booting the machine + # vb.gui = true + # + # # Customize the amount of memory on the VM: + # vb.memory = "1024" + # end + # + # View the documentation for the provider you are using for more + # information on available options. + + # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies + # such as FTP and Heroku are also available. See the documentation at + # https://docs.vagrantup.com/v2/push/atlas.html for more information. + # config.push.define "atlas" do |push| + # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME" + # end + + # Enable provisioning with a shell script. Additional provisioners such as + # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the + # documentation for more information about their specific syntax and use. + # config.vm.provision "shell", inline: <<-SHELL + # apt-get update + # apt-get install -y apache2 + # SHELL +end diff --git a/tests/Vagrant/Vagrantfile.jammy64 b/tests/Vagrant/Vagrantfile.jammy64 new file mode 100644 index 0000000..629d7f7 --- /dev/null +++ b/tests/Vagrant/Vagrantfile.jammy64 @@ -0,0 +1,6 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure(2) do |config| + config.vm.box = "ubuntu/jammy64" +end diff --git a/tests/unit-tests.sh b/tests/unit-tests.sh index 9bd6020..2a28841 100644 --- a/tests/unit-tests.sh +++ b/tests/unit-tests.sh @@ -2,9 +2,11 @@ set -e -while getopts "skip" opt; do +while getopts "s" opt; do case $opt in s) SKIP_SETUP=true ;; + *) echo "usage: $0 [-v] [-r]" >&2 + exit 1 ;; esac done @@ -21,7 +23,6 @@ source "${current_dir}/lib/bunit.shl" source "${current_dir}/../setupLibrary.sh" test_user_account=testuser -test_account_password="123%pass_321" # shellcheck disable=SC2034 VERBOSE_MODE="true" @@ -30,7 +31,7 @@ VERBOSE_MODE="true" function testSetup () { echo "Test Setup" - addUserAccount ${test_user_account} ${test_account_password} true + addUserAccount ${test_user_account} true } function testUserAccountCreated() { @@ -115,7 +116,8 @@ function testNTP() { configureNTP ubuntu_version="$(lsb_release -sr)" - if [[ $ubuntu_version == '18.04' ]]; then + if [[ $(bc -l <<< "${ubuntu_version} >= 18.04") -eq 1 ]]; then + sleep 2 assertContains "System clock synchronized: yes" "$(timedatectl status)" else assertContains "NTP synchronized: yes" "$(timedatectl status)"