diff --git a/Chapter 3 Files/dashboard_update.sh b/Chapter 3 Files/dashboard_update.sh index c00e276c..646fa614 100644 --- a/Chapter 3 Files/dashboard_update.sh +++ b/Chapter 3 Files/dashboard_update.sh @@ -8,7 +8,7 @@ if [ -r /opt/lme/lme.conf ]; then #reference this file as a source . /opt/lme/lme.conf #check if the version number is equal to the one we want - if [ "$version" == "1.0" ]; then + if [ "$version" == "1.2.0" ]; then echo -e "\e[32m[X]\e[0m Updating from git repo" git -C /opt/lme/ pull #make sure the hostname variable is present diff --git a/Chapter 3 Files/deploy.sh b/Chapter 3 Files/deploy.sh index 11504851..cfc78118 100755 --- a/Chapter 3 Files/deploy.sh +++ b/Chapter 3 Files/deploy.sh @@ -3,38 +3,45 @@ # LME Deploy Script # ############################ # This script configures a host for LME including generating certificates and populating configuration files. + +# Put the latest version number here + DATE="$(date '+%Y-%m-%d-%H:%M:%S')" #prompt for y/n prompt() { - if [ -z "$1" ]; - then + if [ -z "$1" ]; then str="Are you sure?" else str=$1 fi - while true - do - read -r -p "$str? [Y/n] " input - - case $input in - [yY][eE][sS]|[yY]) - return 0 #true - break - ;; - [nN][oO]|[nN]) - return 1 #false - break - ;; - *) - echo "Invalid input..." - ;; - esac + while true; do + read -r -p "$str? [Y/n] " input + + case $input in + [yY][eE][sS] | [yY]) + return 0 #true + break + ;; + [nN][oO] | [nN]) + return 1 #false + break + ;; + *) + echo "Invalid input..." + ;; + esac done } +function get_latest_version() { + #TODO: eventually have this pull from github + #return: + echo -n '1.2.0' + return 0 +} function customlogstashconf() { #add option for custom logstash config CUSTOM_LOGSTASH_CONF=/opt/lme/Chapter\ 3\ Files/logstash_custom.conf @@ -48,12 +55,12 @@ function customlogstashconf() { function generatepasswords() { - elastic_user_pass=$(LC_ALL=C tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 32 | head -n 1) - kibana_system_pass=$(LC_ALL=C tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 32 | head -n 1) - logstash_system_pass=$(LC_ALL=C tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 32 | head -n 1) - logstash_writer=$(LC_ALL=C tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 32 | head -n 1) - update_user_pass=$(LC_ALL=C tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 32 | head -n 1) - kibanakey=$(LC_ALL=C tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 42 | head -n 1) + elastic_user_pass=$(LC_ALL=C tr -dc 'a-zA-Z0-9' max_attempts)); then - echo "Elasticsearch is not responding after $max_attempts attempts - exiting." - exit 1 + echo "Elasticsearch is not responding after $max_attempts attempts - exiting." + exit 1 fi done echo "Elasticsearch is up and running." @@ -177,7 +183,6 @@ function zipfiles() { function generateCA() { echo -e "\e[33m[!]\e[0m Note: Depending on your OpenSSL configuration you may see an error opening a .rnd file into RNG, this will not block the installation" - #configure certificate authority mkdir -p certs @@ -406,6 +411,11 @@ function initdockerswarm() { fi } +function pulllme() { + echo -e "\e[32m[X]\e[0m Pulling ELK images" + docker compose -f /opt/lme/Chapter\ 3\ Files/docker-compose-stack-live.yml pull +} + function deploylme() { docker stack deploy lme --compose-file /opt/lme/Chapter\ 3\ Files/docker-compose-stack-live.yml } @@ -421,7 +431,6 @@ get_distribution() { echo "$lsb_dist" } - function indexmappingupdate() { echo -e "\n\e[32m[X]\e[0m Uploading the LME index template" curl --cacert certs/root-ca.crt --user "elastic:$elastic_user_pass" -X PUT "https://127.0.0.1:9200/_index_template/lme_template" -H 'Content-Type: application/json' --data "@winlog-index-mapping.json" @@ -482,7 +491,6 @@ function pipelineupdate() { ' } - function data_retention() { #show ext4 disk DF_OUTPUT="$(df -h -l -t ext4 --output=source,size /var/lib/docker)" @@ -609,12 +617,10 @@ function configelasticsearch() { curl --cacert certs/root-ca.crt --user "elastic:$elastic_user_pass" -X PUT "https://127.0.0.1:9200/_all/_settings" -H 'Content-Type: application/json' -d '{"index" : {"number_of_replicas" : 0}}' } - - function writeconfig() { echo -e "\n\e[32m[X]\e[0m Writing LME Config" #write LME version - echo "version=1.0" >/opt/lme/lme.conf + echo "version=$(get_latest_version)" >/opt/lme/lme.conf if [ -z "$logstashcn" ]; then # $logstashcn is not set - so this function is not called from an initial install read -e -p "Enter the Fully Qualified Domain Name (FQDN) of this Linux server: " logstashcn @@ -651,7 +657,6 @@ function zipnewcerts() { zip -rmT /opt/lme/new_client_certificates.zip /tmp/lme } - function bootstrapindex() { if [[ "$(curl --cacert certs/root-ca.crt --user "elastic:$elastic_user_pass" -s -o /dev/null -w ''%{http_code}'' https://127.0.0.1:9200/winlogbeat-000001)" != "200" ]]; then echo -e "\n\e[32m[X]\e[0m Bootstrapping index alias" @@ -670,18 +675,18 @@ function bootstrapindex() { } function fixreadability() { - cd /opt/lme/ - chmod -077 -R . - - #some permissions to help with seeing files - chown root:sudo /opt/lme/ - chmod 750 /opt/lme/ - chmod 644 files_for_windows.zip - - #fix backups - chown -R 1000:1000 /opt/lme/backups - chmod -R go-rwx /opt/lme/backups - + cd /opt/lme/ + chmod -077 -R . + + #some permissions to help with seeing files + chown root:sudo /opt/lme/ + chmod 750 /opt/lme/ + chmod 644 files_for_windows.zip + + #fix backups + chown -R 1000:1000 /opt/lme/backups + chmod -R go-rwx /opt/lme/backups + } function install() { @@ -725,13 +730,12 @@ function install() { read -e -p "This script will use self signed certificates for communication and encryption. Do you want to continue with self signed certificates? ([y]es/[n]o): " -i "y" selfsignedyn read -e -p "Skip Docker Install? ([y]es/[n]o): " -i "n" skipdinstall - read -e -p "Do you have an old elastic user password? ([y]es/[n]o): " -i "n" old_elastic_user_pass - + read -e -p "Do you have an old elastic user password from a previous LME install? ([y]es/[n]o): " -i "n" old_elastic_user_pass if [ "$old_elastic_user_pass" == "y" ]; then res= false - while [ ! $res ];do - read -e -p "PASSWORD: " OLD_ELASTIC_PASS + while [ ! $res ]; do + read -e -p "PASSWORD: " OLD_ELASTIC_PASS prompt "confirm password \"$OLD_ELASTIC_PASS\"" res=$? done @@ -792,7 +796,6 @@ function install() { echo "Not a valid option" fi - if [ "$skipdinstall" == "n" ]; then installdocker fi @@ -802,6 +805,7 @@ function install() { generatepasswords populatelogstashconfig configuredocker + pulllme deploylme setpasswords configelasticsearch @@ -828,8 +832,8 @@ function install() { #prompt user to enable auto update #Deprecated #promptupdate - - #fix readability: + + #fix readability: fixreadability echo "" @@ -853,7 +857,7 @@ function uninstall() { read -e -p "Proceed ([y]es/[n]o):" -i "n" check if [ "$check" == "n" ]; then return - elif [ "$check" == "y" ];then + elif [ "$check" == "y" ]; then echo -e "\e[32m[X]\e[0m Removing Docker stack and configuration" docker stack rm lme docker secret rm ca.crt logstash.crt logstash.key elasticsearch.key elasticsearch.crt @@ -883,7 +887,7 @@ function upgrade() { crontab -l | sed -E '/lme_update.sh|dashboard_update.sh/d' | crontab - #grab latest version - latest="1.0" + latest=$(get_latest_version) #check if the config file we're now creating on new installs exists if [ -r /opt/lme/lme.conf ]; then @@ -947,6 +951,7 @@ function upgrade() { echo -e "\e[32m[X]\e[0m Recreating Docker stack" docker config create logstash.conf /opt/lme/Chapter\ 3\ Files/logstash.edited.conf docker config create logstash_custom.conf /opt/lme/Chapter\ 3\ Files/logstash_custom.conf + pulllme deploylme if [ -z "$logstashcn" ]; then read -e -p "Enter the Fully Qualified Domain Name (FQDN) of this Linux server: " logstashcn @@ -954,8 +959,34 @@ function upgrade() { zipfiles fixreadability + elif [ "$version" == "1.0" ]; then + echo -e "\e[32m[X]\e[0m Backing up config file to: /opt/lme/Chapter\ 3\ Files/backup_config " + sudo mkdir -p /opt/lme/Chapter\ 3\ Files/backup_config + sudo cp /opt/lme/Chapter\ 3\ Files/docker-compose-stack-live.yml /opt/lme/Chapter\ 3\ Files/backup_config/docker-compose-stack-live.yml + + echo -e "\e[32m[X]\e[0m Updating elastic to 8.11.1 " + sudo sed -i 's/8.7.1/8.11.1/g' /opt/lme/Chapter\ 3\ Files/docker-compose-stack-live.yml + sudo docker stack rm lme + + echo -e "\e[32m[X]\e[0m Sleeping for one minute to allow Docker actions to complete..." + sleep 1m + + pulllme + + echo -e "\e[32m[X]\e[0m Deploy LME" + deploylme + + echo -e "\e[32m[X]\e[0m Copying lme.conf -> lme.conf.bku" + sudo cp -rapf /opt/lme/lme.conf /opt/lme/lme.conf.bku + sudo sed -i "s/version=1.0/version=$latest/g" /opt/lme/lme.conf + + echo -e "\e[32m[X]\e[0m Copying dashboard_update.sh -> dashboard_update.sh.bku" + sudo cp -rapf /opt/lme/dashboard_update.sh /opt/lme/dashboard_update.sh.bku + sudo sed -i "s/\"\$version\" == \"1.0\"/\"\$version\" == \"$latest\"/g" /opt/lme/dashboard_update.sh + + echo -e "\e[32m[X]\e[0m You're on the latest version: $latest!" elif [ "$version" == $latest ]; then - echo -e "\e[32m[X]\e[0m You're on the latest version!" + echo -e "\e[32m[X]\e[0m You're on the latest version!" else echo -e "\e[31m[!]\e[0m Updating directly to LME 1.0 from versions prior to 0.5.1 is not supported. Update to 0.5.1 first." fi @@ -1010,10 +1041,11 @@ function renew() { populatecerts echo -e "\e[32m[X]\e[0m Recreating Docker stack" + pulllme deploylme } -function usage(){ +function usage() { echo -e "\e[31m[!]\e[0m Invalid operation specified" echo "Usage: ./deploy.sh (install/uninstall/renew/upgrade/update)" echo "Example: ./deploy.sh install" diff --git a/Chapter 3 Files/docker-compose-stack.yml b/Chapter 3 Files/docker-compose-stack.yml index 0fb59abd..25d893d7 100644 --- a/Chapter 3 Files/docker-compose-stack.yml +++ b/Chapter 3 Files/docker-compose-stack.yml @@ -5,7 +5,7 @@ version: '3.9' services: elasticsearch: - image: docker.elastic.co/elasticsearch/elasticsearch:8.7.1 + image: docker.elastic.co/elasticsearch/elasticsearch:8.11.1 environment: - node.name=es01 # - discovery.seed_hosts=es01 @@ -65,7 +65,7 @@ services: # depends_on: # elasticsearch: # condition: service_healthy - image: docker.elastic.co/kibana/kibana:8.7.1 + image: docker.elastic.co/kibana/kibana:8.11.1 environment: SERVER_NAME: kibana ELASTICSEARCH_HOSTS: https://elasticsearch:9200 @@ -101,7 +101,7 @@ services: retries: 120 logstash: - image: docker.elastic.co/logstash/logstash:8.7.1 + image: docker.elastic.co/logstash/logstash:8.11.1 environment: XPACK_MONITORING_ENABLED: "false" PIPELINE_ECS_COMPATIBILITY: v8 diff --git a/docs/markdown/maintenance/upgrading.md b/docs/markdown/maintenance/upgrading.md index cf50737f..253c9202 100644 --- a/docs/markdown/maintenance/upgrading.md +++ b/docs/markdown/maintenance/upgrading.md @@ -6,23 +6,30 @@ Below you can find the upgrade paths that are currently supported and what steps Applying these changes is automated for any new installations. But, if you have an existing installation, you need to conduct some extra steps. **Before performing any of these steps it is advised to take a backup of the current installation using the method described [here](/docs/markdown/maintenance/backups.md).** -## 1. Upgrade from 1.0.0 to 1.1.0 -To fetch the latest changes, on the Linux server, run the following commands as root: -``` -cd /opt/lme -git pull -``` +To Upgrade to the latest version from Release 1.1.0 to Release 1.2.0 [go here](#5-upgrade-from-110-to-120). -To manually update the dashboards, see [How to update dashboards](/Chapter%204%20Files/dashboards#how-to-update-dashboards). +## 1. Finding your LME version (and the components versions) +When reporting an issue or suggesting improvements, it is important to include the versions of all the components, where possible. This ensures that the issue has not already been fixed! -Additionally, to fix a potential file permission issue present in v1.0.0, run the following command on the Linux server: -``` -sudo chown -R 1000:1000 /opt/lme/backups -``` +### 1.1. Windows Server +* Operating System: Press "Windows Key"+R and type ```winver``` +* WEC Config: Open EventViewer > Subscriptions > "LME" > Description should contain version number +* Winlogbeat Config: At the top of the file C:\Program Files\lme\winlogbeat.yml there should be a version number. +* Winlogbeat.exe version: Using PowerShell, navigate to the location of the Winlogbeat executable ("C:\Program Files\lme\winlogbeat-x.x.x-windows-x86_64") and run `.\winlogbeat version`. +* Sysmon config: From either the top of the file or look at the status dashboard +* Sysmon executable: Either run sysmon.exe or look at the status dashboard -See [Directory permission issues](/docs/markdown/reference/troubleshooting.md#directory-permission-issues) for more details. +### 1.2. Linux Server +* Docker: on the Linux server type ```docker --version``` +* Linux: on the Linux server type ```cat /etc/os-release``` +* Logstash config: on the Linux server type ```sudo docker config inspect logstash.conf --pretty``` + + +## 2. Upgrade from versions prior to v0.5 +LME does not support upgrading directly from versions prior to 0.5 to 1.0. Prior to switching to CISA's repo, first upgrade to the latest version of LME published by the NCSC (v0.5.1). Then follow the instructions above to upgrade to v1.0. -## 2. Upgrade from v0.5 to 1.0.0 + +## 3. Upgrade from v0.5 to 1.0.0 Since LME's transition from the NCSC to CISA, the location of the LME repository has changed from `https://github.com/ukncsc/lme` to `https://github.com/cisagov/lme`. To obtain any further updates to LME on the ELK server, you will need to transition to the new git repository. Because vital configuration files are stored within the same folder as the git repo, it's simpler to copy the old LME folder to a different location, clone the new repo, copy the files and folders unique to your system, and then optionally delete the old folder. You can do this by running the following commands: @@ -45,12 +52,13 @@ sudo cp /opt/lme/Chapter\ 3\ Files/dashboard_update.sh /opt/lme/ sed -i "s/dashboardupdatepassword/$OLD_Password/g" /opt/lme/dashboard_update.sh ``` -### 2.1. ELK Stack Update + +### 3.1. ELK Stack Update You can update the ELK stack portion of LME to v1.0 (including dashboards and ELK stack containers) by running the following on the Linux server: ``` cd /opt/lme/Chapter\ 3\ Files/ -sudo ./deploy.sh update +sudo ./deploy.sh upgrade ``` **The last step of this script makes all files only readable by their owner in /opt/lme, so that all root owned files with passwords in them are only readable by root. This prevents a local unprivileged user from gaining access to the elastic stack.** @@ -81,7 +89,7 @@ The rules built-in to the Elastic SIEM can then be updated to the latest version -### 2.2. Winlogbeat Update +### 3.2. Winlogbeat Update The winlogbeat.yml file used with LME v0.5.1 is not compatible with Winlogbeat 8.5.0, the version used with LME v1.0. As such, running `./deploy.sh update` from step 1.1.1 regenerates a new config file. **Your client may still authenticate and push logs to elasticsearch, but for both the security of the client and your LME setup we suggest you still update** @@ -91,33 +99,52 @@ To update Winlogbeat: 2. From an elevated PowerShell session, navigate to the location of the Winlogbeat executable ("C:\Program Files\lme\winlogbeat-x.x.x-windows-x86_64\") and then run `./uninstall-service-winlogbeat.ps1` 3. Re-install Winlogbeat, using the new copy of files_for_windows.zip, following the instructions listed under [3.3 Configuring Winlogbeat on Windows Event Collector Server](/docs/markdown/chapter3/chapter3.md#33-configuring-winlogbeat-on-windows-event-collector-server) -### 2.3. Network Share Updates +### 3.3. Network Share Updates LME v1.0 made a minor change to the file structure used in the SYSVOL folder, so a few manual changes are needed to accommodate this. 1. Set up the SYSVOL folder as described in [2.2.1 - Folder Layout](/docs/markdown/chapter2.md#221---folder-layout). 2. Replace the old version of update.bat with the [latest version](/Chapter%202%20Files/GPO%20Deployment/update.bat). 3. Update the path to update.bat used in the LME-Sysmon-Task GPO (refer to [2.2.3 - Scheduled task GPO Policy](/docs/markdown/chapter2.md#223---scheduled-task-gpo-policy)). -### 2.4. Checklist +### 3.4. Checklist 1. Have the ELK stack components been upgraded on the Linux server? While on the Linux server, run `sudo docker ps | grep lme`. Version 8.7.1 of Logstash, Kibana, and Elasticsearch should be running. 2. Has Winlogbeat been updated to version 8.5.0? From Event Collector, using PowerShell, navigate to the location of the Winlogbeat executable ("C:\Program Files\lme\winlogbeat-x.x.x-windows-x86_64") and run `.\winlogbeat version`. 3. Is the LME folder inside SYSVOL properly structured? Refer to the checklist listed at the end of chapter 2. 4. Are the events from all clients visible inside elastic? Refer to [4.1.2 Check you are receiving logs](/docs/markdown/chapter4.md#412-check-you-are-receiving-logs). -## 3. Upgrade from versions prior to v0.5 -LME does not support upgrading directly from versions prior to 0.5 to 1.0. Prior to switching to CISA's repo, first upgrade to the latest version of LME published by the NCSC (v0.5.1). Then follow the instructions above to upgrade to v1.0. -## 4. Finding your LME version (and the components versions) -When reporting an issue or suggesting improvements, it is important to include the versions of all the components, where possible. This ensures that the issue has not already been fixed! +## 4. Upgrade from 1.0.0 to 1.1.0 +To fetch the latest changes, on the Linux server, run the following commands as root: +``` +cd /opt/lme +git pull +``` + +To manually update the dashboards, see [How to update dashboards](/Chapter%204%20Files/dashboards#how-to-update-dashboards). + +Additionally, to fix a potential file permission issue present in v1.0.0, run the following command on the Linux server: +``` +sudo chown -R 1000:1000 /opt/lme/backups +``` + +See [Directory permission issues](/docs/markdown/reference/troubleshooting.md#directory-permission-issues) for more details. + + +## 5. Upgrade from 1.1.0 to 1.2.0 +To fetch the latest changes, on the Linux server, run the following commands as root: +``` +cd /opt/lme/Chapter\ 3\ Files/ +sudo ./deploy.sh uninstall +cd /opt/lme +git pull +cd Chapter\ 3\ Files/ +sudo ./deploy.sh install +``` + +The deploy.sh script should have now created new files on the Linux server at location /opt/lme/files_for_windows.zip . This file needs to be copied across and used on the Windows Event Collector server like it was explained in Chapter 3 sections [3.2.4 & 3.3 ](/docs/markdown/chapter3/chapter3.md#324-download-files-for-windows-event-collector). + +Then reboot your Client computers & Windows Event Collector. On Windows Event Collector open services.msc as an administrator and make sure the winlogbeat service is set to start automatically, and is running. + + + -### 4.1. Windows Server -* Operating System: Press "Windows Key"+R and type ```winver``` -* WEC Config: Open EventViewer > Subscriptions > "LME" > Description should contain version number -* Winlogbeat Config: At the top of the file C:\Program Files\lme\winlogbeat.yml there should be a version number. -* Winlogbeat.exe version: Using PowerShell, navigate to the location of the Winlogbeat executable ("C:\Program Files\lme\winlogbeat-x.x.x-windows-x86_64") and run `.\winlogbeat version`. -* Sysmon config: From either the top of the file or look at the status dashboard -* Sysmon executable: Either run sysmon.exe or look at the status dashboard -### 4.2. Linux Server -* Docker: on the Linux server type ```docker --version``` -* Linux: on the Linux server type ```cat /etc/os-release``` -* Logstash config: on the Linux server type ```sudo docker config inspect logstash.conf --pretty```