diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ff1f297
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+# Ignore the file '/overrideOwnDomain' because this is per host individually.
+/overrideOwnDomain
+
+# Ignore the subfolders only, because their content are other git repositories.
+# But 'definitions and 'states' should be prepared by cloning this repository.
+/definitions/*/
+/states/*/
+
+# Ignore environment files
+.env
diff --git a/README.md b/README.md
index 5eb5fea..6e85076 100644
--- a/README.md
+++ b/README.md
@@ -1,35 +1,109 @@
-Infrastructure System (ISS)
-===========================
+Core Infrastructure System (CIS)
+================================
-Setup a new host
-----------------
+The main idea is to use git to keep scripts, definitions and state in sync across all hosts.
+Currently an operating instance uses one repository for this core functionality and scripts,
+another to distibute the definitions and a third one to share the state.
-### Preconditions
-To deploy the system you have to clone this repository to the host as root user.
-Therefore you have to register the SSH public key of that root user as deploy key to allow readonly access to this repository.
-We use the modern ed25519 keys, so the public key of root is stored at this location:
+If a script or a definition has to be changed an independent working copy is needed to push the adaptions.
+States can be changed by a host itself. Then we need a mechanism that informs all hosts to execute a `git pull`.
+
+We use a Git server as syncronisation point and use a web hook to send the notification.
+Because the should not be an agent to be installed on each host, we use jenkins to execute an update script via ssh.
+
+This allows us to use standard software without having to program something that may contain a security problem.
+
+
+
+Setup the first or a new host
+-----------------------------
+
+1. Update the host and ensure git is installed
+2. Set the long hostname (fqdn)
+3. Create ssh keys for user root (ssh key type ed25519)
+
+You can use this script to do so: [prepareThisHostBeforeCloning.sh](./prepareThisHostBeforeCloning.sh)
+
+
+
+### Ensure the existence of the repositories for your definitions and the state
+
+This should be necessary just if you set up the first host.
+You can use the following scripts to assist the process:
+
+- [prepareDefinitionsRepository.sh](./prepareDefinitionsRepository.sh)
+- [prepareStatesRepository.sh](./prepareStatesRepository.sh)
+
+
+
+### Register the public ssh key of user root
+
+This is an example for `example.net` as domain of the host.
+
+1. __Scripts:__
+ The public ssh key of the root user must be registered as a deploy key for the this repository,
+ which grants __readonly access__.
+
+ A root user of a host should only be able to update the local cloned repository (`cis`) to a new version via `git pull`.
+
+2. __Definitions:__
+ The public ssh key of the root user must be registered as a deploy key for the definitions repository,
+ which grants __readonly access__.
+
+ User root should only be able to update the local cloned repository (`cis-definition-example.net`) to a new version via `git pull`.
+
+3. __States:__
+ The public ssh key of the root user must be registered as a deploy key for the states repository,
+ which grants __write access__.
+
+ User root should be able to push new state to the cloned repository (`cis-state-example.net`) via `git push`.
+
+
+
+### Clone the Infrastructure System (cis) repository and complete the setup
+After you registered the printed root's public key of this host you can clone the repository and execute the setup script:
+```sh
+# Note the tailing '/cis', because we want to clone the repository to that folder
+git clone ssh://git@git.example.dev:22448/cis.git /cis
+
+# Execute the setup script
+/cis/setupCoreOntoThisHost.sh
+```
+
+
+
+
+
+
+
+Setup a new host step by step manually
+--------------------------------------
+
+To deploy cis you have to clone this repository to the host as root user.
+Therefore you have to set the correct long hostname (fqdn) create a pair of ssh keys (key type ed25519) for user root
+and register the SSH public key of root as __deploy key__ to allow readonly access to this repository:
1. First become root:
```sh
sudo -i
```
-2. Set the long hostname:
- ```sh
- hostnamectl set-hostname "the-new-unique-long-hostname (fqdn, eg.: host1.example.net)"
- ```
-
-3. Update Ubuntu:
+2. Update Ubuntu:
```sh
# DO NOT SKIP THIS STEP
apt update; apt upgrade -y
```
-4. Install git if needed:
+3. Install git if needed:
```sh
git --version > /dev/null || apt install git
```
+4. Set the long hostname:
+ ```sh
+ hostnamectl set-hostname "the-new-unique-long-hostname (fqdn, eg.: host1.example.net)"
+ ```
+
5. If not exist generate the ssh key pair and print the public key of the user root:
```sh
# -t type of the key pair
@@ -41,40 +115,17 @@ We use the modern ed25519 keys, so the public key of root is stored at this loca
|| (ssh-keygen \
-t ed25519 \
-f "/root/.ssh/id_ed25519" -q -N "" \
- -C "$(date +%Y%m%d):root@$(hostname -b)" \
+ -C "$(date +%Y%m%d)-root@$(hostname -b)" \
&& cat "/root/.ssh/id_ed25519.pub")
```
- This key has to be registerd via gitea web ui as deploy key into the repositories as documented in chapter "Register public host key".
+ This key has to be registerd via gitea web ui as deploy key into this repository.
-### Register public host key
-This is an example for `example.net` as domain of the host owner.
-
-1. Repository `iss`, allow __readonly__ access only.
-2. Repository `iss-definition-example.net`, allow __readonly__ access only.
-3. Repository `iss-state-example.net`, allow __writable__ access.
-
-
-
-### Clone the Infrastructure System (iss) repository
-After you registered the printed root's public key of this host you can clone the repository and execute the setup script:
-```sh
-# Note the tailing '/iss', because we want to clone the repository to that folder
-git clone ssh://git@git.example.dev:22448/iss.git /iss
-
-# Execute the setup script
-/iss/setupCoreOntoThisHost.sh
-```
-
-
-
-
-
How it works
------------
-We add a webhook to each gitea repository that belongs to ISS:
+We add a webhook to each gitea repository that belongs to CIS:
- __Taget URL:__ https://YOUR.JENKINS.DOMAIN/generic-webhook-trigger/invoke?token=YOUR_TOKEN
- __HTTP-Method:__ POST
- __Trigger On:__ Push Events
@@ -94,11 +145,11 @@ cat "${JENKINS_HOME}/.ssh/id_ed25519.pub" \
|| (ssh-keygen \
-t ed25519 \
-f "${JENKINS_HOME}/.ssh/id_ed25519" -q -N "" \
- -C "$(date +%Y%m%d):$(whoami)@$(echo ${JENKINS_URL} | cut -d/ -f3)" \
+ -C "$(date +%Y%m%d)-$(whoami)@$(echo ${JENKINS_URL} | cut -d/ -f3)" \
&& cat "${JENKINS_HOME}/.ssh/id_ed25519.pub")
# add your host here, note the tailing '&' to run it in parallel
-ssh -o StrictHostKeyChecking=no jenkins@192.168.X.Y /iss/update_repositories.sh ( --scripts | --definitions | --states ) &
+ssh -o StrictHostKeyChecking=no jenkins@192.168.X.Y /cis/updateRepositories.sh ( --scripts | --definitions | --states ) &
#wait for all background processes to complete
wait
diff --git a/core/addAndCheckGitRepository.sh b/core/addAndCheckGitRepository.sh
index 8c5ab80..ac6868f 100755
--- a/core/addAndCheckGitRepository.sh
+++ b/core/addAndCheckGitRepository.sh
@@ -6,10 +6,10 @@
function checkPermissions(){
- local _FOLDER _REPOSITORY
+ local _FOLDER _RIGHTS
_FOLDER="${1:?"Missing first parameter FOLDER"}"
_RIGHTS="${2:?"Missing second parameter RIGHTS"}"
- readonly _FOLDER _REPOSITORY
+ readonly _FOLDER _RIGHTS
[ "${_RIGHTS}" == "readonly" ] \
&& [ -d "${_FOLDER}/.git" ] \
@@ -21,30 +21,9 @@ function checkPermissions(){
&& git -C "${_FOLDER}" push --dry-run &> /dev/null \
&& return 0
- echo "FAIL: The rights of the repository are incorrect: ("$(readlink -f ${0})")"
- echo " - '${_FOLDER}' is not '${_RIGHTS}'"
- echo " - check the settings of gitea."
- return 1
-}
-
-function checkRemoteRepository() {
- local _FOLDER _REPOSITORY
- _FOLDER="${1:?"Missing first parameter FOLDER"}"
- _REPOSITORY="${2:?"Missing second parameter REPOSITORY"}"
- readonly _FOLDER _REPOSITORY
-
- #Should exist after successful clone only, therefore the remote repository exists and was accessible.
- [ -d "${_FOLDER}/.git" ] \
- && return 0
-
- #Checks if repository exists and is accessible.
- ! [ -d "${_FOLDER}/.git" ] \
- && git ls-remote "${_REPOSITORY}" \
- && return 0
-
- echo "FAIL: The remote repository is not accessible: ("$(readlink -f ${0})")"
- echo " - '${_REPOSITORY}'"
- echo " - check the settings of gitea."
+ echo "FAIL: The rights of the repository are incorrect: ("$(readlink -f ${0})")" >&2
+ echo " - '${_FOLDER}' is not '${_RIGHTS}'" >&2
+ echo " - check the settings of gitea." >&2
return 1
}
@@ -54,42 +33,67 @@ function cloneOrPull {
_REPOSITORY="${2:?"Missing second parameter REPOSITORY"}"
readonly _FOLDER _REPOSITORY
- ! [ -d "${_FOLDER}/.git" ] \
- && git clone "${_REPOSITORY}" "${_FOLDER}" &> /dev/null \
- && return 0
-
[ -d "${_FOLDER}/.git" ] \
&& git -C "${_FOLDER}" pull &> /dev/null \
&& return 0
- echo "FAIL: The local repository is not updatable: ("$(readlink -f ${0})")"
- echo " - '${_FOLDER}'"
- echo " - check your network and the permissions in gitea."
+ ! [ -d "${_FOLDER}/.git" ] \
+ && git clone "${_REPOSITORY}" "${_FOLDER}" &> /dev/null \
+ && return 0
+
+ echo "FAIL: The local repository is not updatable: ("$(readlink -f ${0})")" >&2
+ echo " - '${_FOLDER}'" >&2
+ echo " - check your network and the permissions in gitea." >&2
+ return 1
+}
+
+function printRepository(){
+ local _FOLDER _CONFIGURED_REPOSITORY _SUGGESTED_REPOSITORY
+ _FOLDER="${1:?"Missing first parameter FOLDER"}"
+ _CONFIGURED_REPOSITORY="$(git -C "${_FOLDER:?"Missing FOLDER"}" config --get remote.origin.url 2> /dev/null)"
+ _SUGGESTED_REPOSITORY="${2}"
+ readonly _FOLDER _CONFIGURED_REPOSITORY _SUGGESTED_REPOSITORY
+
+ ! [ -z "${_CONFIGURED_REPOSITORY}" ] \
+ && echo "${_CONFIGURED_REPOSITORY}" \
+ && return 0
+
+ while true; do
+ read -e -p "Enter ssh URL to clone Repository: " -i "${_SUGGESTED_REPOSITORY}" _REPOSITORY
+ echo "${_REPOSITORY}" | grep -F 'git@' &> /dev/null \
+ && git ls-remote "${_REPOSITORY}" &> /dev/null \
+ && echo "${_REPOSITORY:?"Missing REPOSITORY: e.g. ssh://git@your.domain.com/cis.git"}" \
+ && return 0
+ done
+
+ echo "FAIL: The remote repository is not accessible: ("$(readlink -f ${0})")" >&2
+ echo " - '${_REPOSITORY}'" >&2
+ echo " - check the settings of gitea." >&2
return 1
}
# Note that an unprivileged user can use this script successfully,
# if no user has to be added to the host because it already exists.
function addAndCheckGitRepository() {
- local _FOLDER _REPOSITORY
+ local _FOLDER _REPOSITORY _RIGHTS
_FOLDER="${1:?"Missing first parameter FOLDER"}"
- _REPOSITORY="${2:?"Missing second parameter REPOSITORY: e.g. ssh://git@your.domain.com/iss.git "}"
- _RIGHTS="${3:?"Missing third parameter RIGHTS: (readonly, writable) "}"
- readonly _FOLDER _REPOSITORY
+ _RIGHTS="${2:?"Missing second parameter RIGHTS: (readonly, writable) "}"
+ _REPOSITORY="$(printRepository "${_FOLDER}" "${3}")"
+ readonly _FOLDER _REPOSITORY _RIGHTS
- checkRemoteRepository "${_FOLDER}" "${_REPOSITORY}" \
- && cloneOrPull "${_FOLDER}" "${_REPOSITORY}" \
+ echo \
+ && cloneOrPull "${_FOLDER}" "${_REPOSITORY:?"Missing REPOSITORY: e.g. ssh://git@your.domain.com/cis.git"}" \
&& checkPermissions "${_FOLDER}" "${_RIGHTS}" \
&& echo "SUCCESS: The git repository is usable. ("$(readlink -f ${0})")" \
&& echo " - remote repository: '${_REPOSITORY}'" \
&& echo " - local repository: '${_FOLDER}' (${_RIGHTS})" \
&& return 0
- echo "FAIL: The repository is not functional: ("$(readlink -f ${0})")"
- echo " - remote repository: '${_REPOSITORY}'"
- echo " - local repository: '${_FOLDER}'"
- echo " - due to an error or insufficient rights or"
- echo " - one check failed."
+ echo "FAIL: The repository is not functional: ("$(readlink -f ${0})")" >&2
+ echo " - remote repository: '${_REPOSITORY}'" >&2
+ echo " - local repository: '${_FOLDER}'" >&2
+ echo " - due to an error or insufficient rights or" >&2
+ echo " - one check failed." >&2
return 1
}
@@ -98,4 +102,6 @@ addAndCheckGitRepository \
"$(echo ${1} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
"$(echo ${2} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
"$(echo ${3} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
- && exit 0 || exit 1
+ && exit 0
+
+exit 1
diff --git a/core/addNormalUser.sh b/core/addNormalUser.sh
index 04716c1..7582033 100755
--- a/core/addNormalUser.sh
+++ b/core/addNormalUser.sh
@@ -18,6 +18,8 @@ function addNormalUser() {
&& echo " - '${_USER}'" \
&& return 0
+ # useradd is a low level utility ... use adduser(8) instead.
+ # See: https://askubuntu.com/questions/345974/what-is-the-difference-between-adduser-and-useradd
[ "$(id -u)" == "0" ] \
&& adduser --gecos 'Normal user' --disabled-password "${_USER}" \
&& chown -R "${_USER}:${_USER}" "/home/${_USER}" \
@@ -27,13 +29,14 @@ function addNormalUser() {
&& echo " - existing home directories were taken over" \
&& return 0
- echo "FAIL: The user could not be created: ("$(readlink -f ${0})")"
- echo " - '${_USER}'"
- echo " - due to an error or insufficient rights."
+ echo "FAIL: The user could not be created: ("$(readlink -f ${0})")" >&2
+ echo " - '${_USER}'" >&2
+ echo " - due to an error or insufficient rights." >&2
return 1
}
# sanitizes all parameters
-addNormalUser \
- "$(echo ${1} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
- && exit 0 || exit 1
+addNormalUser "$(echo ${1} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
+ && exit 0
+
+exit 1
diff --git a/core/addToCrontabEveryHour.sh b/core/addToCrontabEveryHour.sh
index 492ad14..e7e7218 100755
--- a/core/addToCrontabEveryHour.sh
+++ b/core/addToCrontabEveryHour.sh
@@ -5,14 +5,17 @@
+# Folders always ends with an tailing '/'
+_SCRIPT="$(readlink -f "${0}" 2> /dev/null)"
+_CIS_ROOT="${_SCRIPT%%/core/*}/" #Removes longest matching pattern '/core/*' from the end
+
# Note that an unprivileged user can use this script successfully,
# if no user has to be added to the host because it already exists.
function addToCrontabEveryHour() {
- local _ROOT _MINUTE_VALUE _STRING
- _ROOT="${0%%/core/*}/" #Removes longest matching pattern '/core/*' from the end
+ local _MINUTE_VALUE _STRING
! [ -z "${2##*[!0-9]*}" ] && _MINUTE_VALUE=$((${2}%60)) # if second parameter is integer then (minute-value % 60) as safe guard
_STRING="${_MINUTE_VALUE:?"Missing MINUTE_VALUE"} * * * * ${1:?"Missing first parameter COMMAND"} > /dev/null 2>&1"
- readonly _ROOT _MINUTE_VALUE _STRING
+ readonly _MINUTE_VALUE _STRING
[ "$(id -u)" == "0" ] \
&& crontab -l | grep -qF "${_STRING:?"Missing CRON_STRING"}" \
@@ -21,11 +24,11 @@ function addToCrontabEveryHour() {
&& return 0
[ "$(id -u)" == "0" ] \
- && echo "${_ROOT:?"Missing ROOT"}" | grep "home" &> /dev/null \
+ && echo "${_CIS_ROOT:?"Missing CIS_ROOT"}" | grep -F 'home' &> /dev/null \
&& echo "SUCCESS: Although the entry will be skipped: ("$(readlink -f ${0})")" \
&& echo " - '${_STRING}'" \
&& echo " that is because the current environment is:" \
- && echo " - ${_ROOT}" \
+ && echo " - ${_CIS_ROOT}" \
&& return 0
[ "$(id -u)" == "0" ] \
@@ -37,9 +40,9 @@ function addToCrontabEveryHour() {
&& echo " - '${_STRING}'" \
&& return 0
- echo "FAIL: Entry could not be registered to crontab: ("$(readlink -f ${0})")"
- echo " - '${_STRING:?"Missing CRON_STRING"}'"
- echo " - due to an error or insufficient rights."
+ echo "FAIL: Entry could not be registered to crontab: ("$(readlink -f ${0})")" >&2
+ echo " - '${_STRING:?"Missing CRON_STRING"}'" >&2
+ echo " - due to an error or insufficient rights." >&2
return 1
}
@@ -47,4 +50,6 @@ function addToCrontabEveryHour() {
addToCrontabEveryHour \
"$(echo ${1} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
"$(echo ${2} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
- && exit 0 || exit 1
+ && exit 0
+
+exit 1
diff --git a/core/default/etc/sudoers.d/allow-jenkins-updateRepositories b/core/default/etc/sudoers.d/allow-jenkins-updateRepositories
new file mode 100644
index 0000000..804dba5
--- /dev/null
+++ b/core/default/etc/sudoers.d/allow-jenkins-updateRepositories
@@ -0,0 +1,6 @@
+Cmnd_Alias C_JENKINS = \
+ /cis/updateRepositories.sh --core, \
+ /cis/updateRepositories.sh --scripts, \
+ /cis/updateRepositories.sh --definitions, \
+ /cis/updateRepositories.sh --states
+jenkins ALL = (root) NOPASSWD: C_JENKINS
diff --git a/core/defineAuthorizedKeysOfUser.sh b/core/defineAuthorizedKeysOfUser.sh
index 68b318e..6b9cb23 100755
--- a/core/defineAuthorizedKeysOfUser.sh
+++ b/core/defineAuthorizedKeysOfUser.sh
@@ -44,24 +44,24 @@ function prepareFolder() {
&& echo " - '${_SSH_FOLDER}'" \
&& return 0
- echo "FAIL: The ssh folder could not be prepared: ("$(readlink -f ${0})")"
- echo " - '${_SSH_FOLDER}'"
- echo " - due to an error or insufficient rights."
+ echo "FAIL: The ssh folder could not be prepared: ("$(readlink -f ${0})")" >&2
+ echo " - '${_SSH_FOLDER}'" >&2
+ echo " - due to an error or insufficient rights." >&2
return 1
}
function defineAuthorizedKeysOfUser() {
- local _ROOT _CORE_SCRIPTS _DOMAIN _DEFINITIONS _USER
+ local _CIS_ROOT _CORE_SCRIPTS _DOMAIN _DEFINITIONS _USER
_DEFINITIONS="$(realpath -s "${1:?"Missing first parameter DEFINITIONS: 'ROOT/definitions/DOMAIN'"}")"
- _ROOT="${_DEFINITIONS%%/definitions/*}/" #Removes longest matching pattern '/definitions/*' from the end
- _DOMAIN="${_DEFINITIONS##*/definitions/}" #Removes longest matching pattern '*/definitions/' from the begin
- _DOMAIN="${_DOMAIN%/}" #Removes shortest matching pattern '/' from the end
+ _CIS_ROOT="${_DEFINITIONS%%/definitions/*}/" #Removes longest matching pattern '/definitions/*' from the end
+ _DOMAIN="${_DEFINITIONS##*/definitions/}" #Removes longest matching pattern '*/definitions/' from the begin
+ _DOMAIN="${_DOMAIN%/}" #Removes shortest matching pattern '/' from the end
#Build from components for safety
- _DEFINITIONS="${_ROOT:?"Missing ROOT"}definitions/${_DOMAIN:?"Missing DOMAIN"}"
+ _DEFINITIONS="${_CIS_ROOT:?"Missing ROOT"}definitions/${_DOMAIN:?"Missing DOMAIN"}"
_USER="${2:?"Missing second parameter USER"}"
- _CORE_SCRIPTS="${_ROOT:?"Missing ROOT"}core/"
- readonly _ROOT _CORE_SCRIPTS _DOMAIN _DEFINITIONS _USER
+ _CORE_SCRIPTS="${_CIS_ROOT:?"Missing ROOT"}core/"
+ readonly _CIS_ROOT _CORE_SCRIPTS _DOMAIN _DEFINITIONS _USER
case "${_USER:?"Missing USER"}" in
root)
@@ -83,4 +83,6 @@ function defineAuthorizedKeysOfUser() {
defineAuthorizedKeysOfUser \
"$(echo ${1} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
"$(echo ${2} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
- && exit 0 || exit 1
+ && exit 0
+
+exit 1
diff --git a/core/ensureUsageOfDefinitions.sh b/core/ensureUsageOfDefinitions.sh
index f9b53b1..05073e3 100755
--- a/core/ensureUsageOfDefinitions.sh
+++ b/core/ensureUsageOfDefinitions.sh
@@ -12,46 +12,76 @@ function printIfEqual() {
}
function isCoreDefinition() {
- echo "${1:?"Missing first parameter FILE"}" | grep "/root/.ssh/authorized_keys" &> /dev/null \
+ echo "${1:?"Missing first parameter FILE"}" | grep -F '/root/.ssh/authorized_keys' &> /dev/null \
&& return 0
- echo "${1:?"Missing first parameter FILE"}" | grep "/home/jenkins/.ssh/authorized_keys" &> /dev/null \
+ echo "${1:?"Missing first parameter FILE"}" | grep -F '/home/jenkins/.ssh/authorized_keys' &> /dev/null \
&& return 0
- echo "${1:?"Missing first parameter FILE"}" | grep "/etc/sudoers.d/allow-jenkins-updateRepositories" &> /dev/null \
+ echo "${1:?"Missing first parameter FILE"}" | grep -F '/etc/sudoers.d/allow-jenkins-updateRepositories' &> /dev/null \
&& return 0
return 1
}
+function filterInvalidAuthorizedKeysFilesOfRoot() {
+ local _FILE_DEFINED
+ _FILE_DEFINED="${1:?"Missing DEFINITION FILE"}"
+ readonly _FILE_DEFINED
+
+ #If the full filename contains 'root/.ssh/authorized_keys' then check the content.
+ #Skip lines starting with '#' and if at least one remaining line contains 'ssh' and '@' then print the filename.
+ echo "${_FILE_DEFINED}" | grep -F 'root/.ssh/authorized_keys' &> /dev/null \
+ && grep -vE '^[[:blank:]]*#' "${_FILE_DEFINED}" | grep -F 'ssh' | grep -F '@' &> /dev/null \
+ && echo "${_FILE_DEFINED}" \
+ && return 0
+
+ #If the full filename contains 'root/.ssh/authorized_keys' print nothing because the file has to be invalid.
+ echo "${_FILE_DEFINED}" | grep -F 'root/.ssh/authorized_keys' &> /dev/null \
+ && echo \
+ && return 0
+
+ #Print the full filename because it does not contain 'root/.ssh/authorized_keys'
+ echo "${_FILE_DEFINED}"
+ return 0
+}
+
function printSelectedDefinition() {
- local _CORE_FILE_DEFINED_ALL_HOSTS _CORE_FILE_DEFINED_THIS_HOST _FILE_DEFINED_ALL_HOSTS _FILE_DEFINED_THIS_HOST
- _CORE_FILE_DEFINED_ALL_HOSTS="${1:?"Missing DEFINITIONS"}/core/all${2:?"Missing CURRENT_FULLFILE"}"
- _CORE_FILE_DEFINED_THIS_HOST="${1:?"Missing DEFINITIONS"}/core/$(hostname -s)${2:?"Missing CURRENT_FULLFILE"}"
- _FILE_DEFINED_ALL_HOSTS="${1:?"Missing DEFINITIONS"}/hosts/all${2:?"Missing CURRENT_FULLFILE"}"
- _FILE_DEFINED_THIS_HOST="${1:?"Missing DEFINITIONS"}/hosts/$(hostname -s)${2:?"Missing CURRENT_FULLFILE"}"
- readonly _CORE_FILE_DEFINED_ALL_HOSTS _CORE_FILE_DEFINED_THIS_HOST _FILE_DEFINED_ALL_HOSTS _FILE_DEFINED_THIS_HOST
+ local _DEFINITIONS _CORE_FILE_DEFINED_ALL_HOSTS _CORE_FILE_DEFINED_THIS_HOST _FILE_DEFINED_ALL_HOSTS _FILE_DEFINED_THIS_HOST
+ _DEFINITIONS="${1:?"Missing CIS_ROOT"}definitions/${2:?"Missing DOMAIN"}/"
+ _CORE_DEFAULT_ALL_HOSTS="${1:?"Missing CIS_ROOT"}core/default${3:?"Missing CURRENT_FULLFILE"}"
+ _CORE_FILE_DEFINED_ALL_HOSTS="${_DEFINITIONS:?"Missing DEFINITIONS"}core/all${3:?"Missing CURRENT_FULLFILE"}"
+ _CORE_FILE_DEFINED_THIS_HOST="${_DEFINITIONS:?"Missing DEFINITIONS"}core/$(hostname -s)${3:?"Missing CURRENT_FULLFILE"}"
+ _FILE_DEFINED_ALL_HOSTS="${_DEFINITIONS:?"Missing DEFINITIONS"}hosts/all${3:?"Missing CURRENT_FULLFILE"}"
+ _FILE_DEFINED_THIS_HOST="${_DEFINITIONS:?"Missing DEFINITIONS"}hosts/$(hostname -s)${3:?"Missing CURRENT_FULLFILE"}"
+ readonly _DEFINITIONS _CORE_FILE_DEFINED_ALL_HOSTS _CORE_FILE_DEFINED_THIS_HOST _FILE_DEFINED_ALL_HOSTS _FILE_DEFINED_THIS_HOST
#The following are special definitions that affect the core functionality.
#Try this host first because it should be priorized.
- isCoreDefinition "${2:?"Missing CURRENT_FULLFILE"}" \
+ isCoreDefinition "${3:?"Missing CURRENT_FULLFILE"}" \
&& [ -s "${_CORE_FILE_DEFINED_THIS_HOST}" ] \
- && echo "${_CORE_FILE_DEFINED_THIS_HOST}" \
+ && filterInvalidAuthorizedKeysFilesOfRoot "${_CORE_FILE_DEFINED_THIS_HOST}" \
&& return 0
#The following are special definitions that affect the core functionality.
- isCoreDefinition "${2:?"Missing CURRENT_FULLFILE"}" \
+ isCoreDefinition "${3:?"Missing CURRENT_FULLFILE"}" \
&& [ -s "${_CORE_FILE_DEFINED_ALL_HOSTS}" ] \
- && echo "${_CORE_FILE_DEFINED_ALL_HOSTS}" \
+ && filterInvalidAuthorizedKeysFilesOfRoot "${_CORE_FILE_DEFINED_ALL_HOSTS}" \
+ && return 0
+
+ #The following are special definitions that affect the core functionality.
+ isCoreDefinition "${3:?"Missing CURRENT_FULLFILE"}" \
+ && [ -s "${_CORE_DEFAULT_ALL_HOSTS}" ] \
+ && filterInvalidAuthorizedKeysFilesOfRoot "${_CORE_DEFAULT_ALL_HOSTS}" \
&& return 0
#Try this host first because it should be priorized.
- ! isCoreDefinition "${2:?"Missing CURRENT_FULLFILE"}" \
+ ! isCoreDefinition "${3:?"Missing CURRENT_FULLFILE"}" \
&& [ -s "${_FILE_DEFINED_THIS_HOST}" ] \
&& echo "${_FILE_DEFINED_THIS_HOST}" \
&& return 0
- ! isCoreDefinition "${2:?"Missing CURRENT_FULLFILE"}" \
+ ! isCoreDefinition "${3:?"Missing CURRENT_FULLFILE"}" \
&& [ -s "${_FILE_DEFINED_ALL_HOSTS}" ] \
&& echo "${_FILE_DEFINED_ALL_HOSTS}" \
&& return 0
@@ -71,11 +101,6 @@ function createSymlinkToDefinition() {
&& [ "$(sha256sum "${_DEFINED_FULLFILE}" | cut -d' ' -f1)" == "$(sha256sum "${_CURRENT_FULLFILE}" | cut -d' ' -f1)" ] \
&& echo "The content of the current file already matches the definition, but it will be replaced by a symlink..."
- [ -f "${_CURRENT_FULLFILE}" ] \
- && [ "$(sha256sum "${_DEFINED_FULLFILE}" | cut -d' ' -f1)" == "$(sha256sum "${_CURRENT_FULLFILE}" | cut -d' ' -f1)" ] \
- && echo "The content of the current file already matches the definition, but it will be replaced by a symlink..."
-
-
[ -f "${_CURRENT_FULLFILE}" ] \
&& mv "${_CURRENT_FULLFILE:?"Missing CURRENT_FULLFILE"}" "${_SAVED_FULLFILE:?"Missing SAVED_FULLFILE"}" \
&& echo "Current file has been backed up to: '${_SAVED_FULLFILE}'"
@@ -92,17 +117,17 @@ function createSymlinkToDefinition() {
}
function ensureUsageOfDefinitions() {
- local _ROOT _CURRENT_FILE _CURRENT_FOLDER _CURRENT_FULLFILE _DEFINITIONS _DOMAIN _DEFINED_FULLFILE _NOW _SAVED_FULLFILE
- _DEFINITIONS="$(realpath -s "${1:?"Missing first parameter DEFINITIONS: 'ROOT/definitions/DOMAIN'"}")"
- _ROOT="${_DEFINITIONS%%/definitions/*}/" #Removes longest matching pattern '/definitions/*' from the end
- _DOMAIN="${_DEFINITIONS##*/definitions/}" #Removes longest matching pattern '*/definitions/' from the begin
- _DOMAIN="${_DOMAIN%/}" #Removes shortest matching pattern '/' from the end
+ local _CIS_ROOT _CURRENT_FILE _CURRENT_FOLDER _CURRENT_FULLFILE _DEFINITIONS _DOMAIN _DEFINED_FULLFILE _NOW _SAVED_FULLFILE
+ _DEFINITIONS="$(realpath -s "${1:?"Missing first parameter DEFINITIONS: 'ROOT/definitions/DOMAIN'"}")/"
+ _CIS_ROOT="${_DEFINITIONS%%/definitions/*}/" #Removes longest matching pattern '/definitions/*' from the end
+ _DOMAIN="${_DEFINITIONS##*/definitions/}" #Removes longest matching pattern '*/definitions/' from the begin
+ _DOMAIN="${_DOMAIN%/}" #Removes shortest matching pattern '/' from the end
#Build from components for safety
- _DEFINITIONS="$(printIfEqual "${_DEFINITIONS}" "${_ROOT:?"Missing ROOT"}definitions/${_DOMAIN:?"Missing DOMAIN"}")"
+ _DEFINITIONS="$(printIfEqual "${_DEFINITIONS}" "${_CIS_ROOT:?"Missing ROOT"}definitions/${_DOMAIN:?"Missing DOMAIN"}/")"
- _CURRENT_FOLDER="$(dirname "${2:?"Missing second parameter CURRENT_FULLFILE"}")"
- _CURRENT_FOLDER="${_CURRENT_FOLDER%/}/" #Removes shortest matching pattern '/' from the end
+ _CURRENT_FULLFILE="${2:?"Missing second parameter CURRENT_FULLFILE"}"
+ _CURRENT_FOLDER="${_CURRENT_FULLFILE%/*}/" #Removes shortest matching pattern '/*' from the end
! [ -d "${_CURRENT_FOLDER}" ] \
&& echo "FAIL: The folder cannot be read: ("$(readlink -f ${0})")" \
&& echo " - '${_CURRENT_FOLDER}'" \
@@ -118,10 +143,16 @@ function ensureUsageOfDefinitions() {
_CURRENT_FULLFILE="${_CURRENT_FOLDER:?"Missing CURRENT_FOLDER"}${_CURRENT_FILE:?"Missing CURRENT_FILE"}"
- _DEFINED_FULLFILE="$(printSelectedDefinition "${_DEFINITIONS}" "${_CURRENT_FULLFILE}")"
+ _DEFINED_FULLFILE="$(printSelectedDefinition "${_CIS_ROOT}" "${_DOMAIN}" "${_CURRENT_FULLFILE}")"
_NOW="$(date +%Y%m%d_%H%M)"
- _SAVED_FULLFILE="${_CURRENT_FULLFILE}-backup@${_NOW:?"Missing NOW"}"
- readonly _ROOT _CURRENT_FILE _CURRENT_FOLDER _CURRENT_FULLFILE _DEFINITIONS _DOMAIN _DEFINED_FULLFILE _NOW _SAVED_FULLFILE
+ _SAVED_FULLFILE="${_CURRENT_FULLFILE}.backup@${_NOW:?"Missing NOW"}"
+ readonly _CIS_ROOT _CURRENT_FILE _CURRENT_FOLDER _CURRENT_FULLFILE _DEFINITIONS _DOMAIN _DEFINED_FULLFILE _NOW _SAVED_FULLFILE
+
+ [ -z "${_DEFINED_FULLFILE}" ] \
+ && echo \
+ && echo "URGENT WARNING: If an 'authorized_keys' file of root is replaced by an invalid version," \
+ && echo " you may lose access to this host!" \
+ && echo
! [ -f "${_DEFINED_FULLFILE}" ] \
&& echo "FAIL: No definition available for this file: ("$(readlink -f ${0})")" \
@@ -138,11 +169,11 @@ function ensureUsageOfDefinitions() {
&& echo " - '${_DEFINED_FULLFILE}'" \
&& return 0
- echo "${_ROOT:?"Missing ROOT"}" | grep "home" &> /dev/null \
+ echo "${_CIS_ROOT:?"Missing CIS_ROOT"}" | grep -F 'home' &> /dev/null \
&& echo "SUCCESS: Although this definition will be skipped: ("$(readlink -f ${0})")" \
&& echo " - '${_DEFINED_FULLFILE}'" \
&& echo " that is because the current environment is:" \
- && echo " - ${_ROOT}" \
+ && echo " - ${_CIS_ROOT}" \
&& echo " following file is in use:" \
&& echo " - $(readlink -f "${_CURRENT_FULLFILE}")" \
&& return 0
@@ -165,8 +196,8 @@ function ensureUsageOfDefinitions() {
&& echo "- '${_DEFINED_FULLFILE}'" \
&& return 0
- echo "FAIL: The definition could not be ensured: ("$(readlink -f ${0})")"
- echo " - due to an error or insufficient rights."
+ echo "FAIL: The definition could not be ensured: ("$(readlink -f ${0})")" >&2
+ echo " - due to an error or insufficient rights." >&2
return 1
}
@@ -174,4 +205,6 @@ function ensureUsageOfDefinitions() {
ensureUsageOfDefinitions \
"$(echo ${1} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
"$(echo ${2} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
- && exit 0 || exit 1
+ && exit 0
+
+exit 1
diff --git a/core/printCisRoot.sh b/core/printCisRoot.sh
new file mode 100755
index 0000000..67bc2db
--- /dev/null
+++ b/core/printCisRoot.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+_SCRIPT="$(readlink -f "${0}" 2> /dev/null)"
+_CIS_ROOT="${_SCRIPT%%/core/*}/" #Removes longest matching pattern '/core/*' from the end
+
+[ -d "${_CIS_ROOT}" ] \
+ && [ -d "${_CIS_ROOT}definitions/" ] \
+ && [ -d "${_CIS_ROOT}states/" ] \
+ && echo "${_CIS_ROOT}" \
+ && exit 0
+
+echo "FAIL: Unable to detect CIS_ROOT" >&2
+exit 1
diff --git a/core/printOwnDomain.sh b/core/printOwnDomain.sh
new file mode 100755
index 0000000..a5e712d
--- /dev/null
+++ b/core/printOwnDomain.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+#WARNING: Used for core functionality in setup.sh
+# DO NOT rename the script and test changes well!
+
+
+
+# Folders always ends with an tailing '/'
+_SCRIPT="$(readlink -f "${0}" 2> /dev/null)"
+_CIS_ROOT="${_SCRIPT%%/core/*}/" #Removes longest matching pattern '/core/*' from the end
+_OVERRIDE_DOMAIN_FILE="${_CIS_ROOT:?"Missing CIS_ROOT"}overrideOwnDomain"
+
+# There has to be one dot at least.
+_BOOT_DOMAIN="$(hostname -b | grep -F '.' | cut -d. -f2-)"
+
+# Take OVERRIDING_DOMAIN_FILE without empty lines and comments, then take the first line without leading spaces
+_OVERRIDE_DOMAIN="$(grep -vE '^[[:space:]]*$|^[[:space:]]*#' "${_OVERRIDE_DOMAIN_FILE}" 2> /dev/null | head -n 1 | xargs)"
+
+! [ -z "${_OVERRIDE_DOMAIN}" ] \
+ && [ "${_OVERRIDE_DOMAIN}" != "${_BOOT_DOMAIN}" ] \
+ && echo "WARNING: Domain has been overridden by: ${_OVERRIDE_DOMAIN_FILE}" >&2 \
+ && echo "${_OVERRIDE_DOMAIN}" \
+ && exit 0
+
+! [ -z "${_BOOT_DOMAIN}" ] \
+ && echo "${_BOOT_DOMAIN}" \
+ && exit 0
+
+echo "It was impossible to find out the domain of this host, please prepare this host first." >&2
+exit 1
diff --git a/prepareDefinitionsRepository.sh b/prepareDefinitionsRepository.sh
new file mode 100755
index 0000000..271f432
--- /dev/null
+++ b/prepareDefinitionsRepository.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+[ "$(id -u)" != "0" ] \
+ && echo "This script prepares the user 'root' of this host and the host itself," \
+ && echo "so this script is allowed to be executed if you are root only." \
+ && exit 1
+
+# There has to be one dot at least.
+_BOOT_DOMAIN="$(hostname -b | grep -F '.' | cut -d. -f2-)"
+
+[ -z "${_BOOT_DOMAIN}" ] \
+ && echo "It was impossible to find out the domain of this host, please prepare this host first." \
+ && exit 1
+
+_REOPSITORY_NAME="cis-definition-${_BOOT_DOMAIN}"
+
+
+
+#Generate file 'README.md'
+mkdir -p /tmp/skeleton/definition
+cat << EOF > /tmp/skeleton/definition/README.md
+This repository contains the definitions of the domain “$_BOOT_DOMAIN” by the Core Infrastructure System.
+EOF
+
+
+
+#Use current file 'authorized_keys' of root as definition
+mkdir -p /tmp/skeleton/definition/core/all/root/.ssh
+cp /root/.ssh/authorized_keys /tmp/skeleton/definition/core/all/root/.ssh/authorized_keys
+
+
+
+#Generate file 'authorized_keys' for user jenkins
+mkdir -p /tmp/skeleton/definition/core/all/home/jenkins/.ssh
+cat << EOF > /tmp/skeleton/definition/core/all/home/jenkins/.ssh/authorized_keys
+#------------------------------------------------------
+# Enter the public ssh key of your jenkins server here.
+#------------------------------------------------------
+EOF
+
+
+
+cat << EOF
+
+The first content for your repository for the definitions of the '$_BOOT_DOMAIN' domain has been created.
+
+Please create a definition repository.
+To follow the naming convention name it '$_REOPSITORY_NAME'
+
+Please DO NOT use the SSH key of root for this.
+Maybe you can use https and user password for pushing the first commit.
+
+Go to folder '/tmp/skeleton/definition' and check the content of all 'authorized_keys' files,
+correct them if required to prevent losing access to your hosts.
+
+The public ssh key of your jenkins server has to be added.
+
+Only now follow the instructions as our git server shows.
+For example:
+
+ cd /tmp/skeleton/definition
+ git init
+ git checkout -b main
+ git add .
+ git commit -m "first core definitions"
+ git remote add origin https://git.example.dev/[SOME_PATH/]$_REOPSITORY_NAME.git
+ git push -u origin main
+
+EOF
diff --git a/prepareStatesRepository.sh b/prepareStatesRepository.sh
new file mode 100755
index 0000000..a68e03e
--- /dev/null
+++ b/prepareStatesRepository.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+[ "$(id -u)" != "0" ] \
+ && echo "This script prepares the user 'root' of this host and the host itself," \
+ && echo "so this script is allowed to be executed if you are root only." \
+ && exit 1
+
+# There has to be one dot at least.
+_BOOT_DOMAIN="$(hostname -b | grep -F '.' | cut -d. -f2-)"
+
+[ -z "${_BOOT_DOMAIN}" ] \
+ && echo "It was impossible to find out the domain of this host, please prepare this host first." \
+ && exit 1
+
+_REOPSITORY_NAME="cis-state-${_BOOT_DOMAIN}"
+
+
+
+#Generate README.md
+mkdir -p /tmp/skeleton/state
+cat << EOF > /tmp/skeleton/state/README.md
+This repository contains the states of the domain “$_BOOT_DOMAIN” by the Core Infrastructure System.
+EOF
+
+
+
+cat << EOF
+
+The first content for your repository for the state of the '$_BOOT_DOMAIN' domain has been created.
+
+Please create a states repository.
+To follow the naming convention name it '$_REOPSITORY_NAME'
+
+Please DO NOT use the SSH key of root for this.
+Maybe you can use https and user password for pushing the first commit.
+
+Then go to folder '/tmp/skeleton/state' and follow the instructions as your git server shows.
+For example:
+
+ cd /tmp/skeleton/state
+ git init
+ git checkout -b main
+ git add .
+ git commit -m "first state"
+ git remote add origin https://git.example.dev/[SOME_PATH/]$_REOPSITORY_NAME.git
+ git push -u origin main
+
+EOF
diff --git a/preparationBeforeCloning.sh b/prepareThisHostBeforeCloning.sh
similarity index 52%
rename from preparationBeforeCloning.sh
rename to prepareThisHostBeforeCloning.sh
index 74d60b4..58aaaa0 100755
--- a/preparationBeforeCloning.sh
+++ b/prepareThisHostBeforeCloning.sh
@@ -8,46 +8,66 @@
function setNeededHostnameOrExit() {
_FQDN="${1:?"Missing unique long hostname (fqdn, eg.: host1.example.net) for this host as first parameter."}"
- echo "${_FQDN}" | grep '\.' &> /dev/null \
+ echo "${_FQDN}" | grep -F '.' &> /dev/null \
&& hostnamectl set-hostname "${_FQDN}" \
&& return 0
- echo "FAILED: setting full qualified domain name, given value was:"
- echo " - ${_FQDN}"
+ echo "FAILED: setting full qualified domain name does not contain a domain,"
+ echo " given value was: ${_FQDN}"
exit 1
}
-function prepare() {
+function prepareThisHost() {
git --version > /dev/null || (apt update; apt upgrade -y; apt install git)
echo
echo "Public SSH-Key for root@$(hostname -b):"
+ cat "/root/.ssh/id_ed25519.pub" \
+ && return 0
+
# -t type of the key pair
# -f defines the filenames (we use the standard for the selected type here)
# -q quiet, no output or interaction
# -N "" means the private key will not be secured by a passphrase
# -C defines a comment
+ ssh-keygen \
+ -t ed25519 \
+ -f "/root/.ssh/id_ed25519" -q -N "" \
+ -C "$(date +%Y%m%d)-root@$(hostname -b)"
+
cat "/root/.ssh/id_ed25519.pub" \
- || (ssh-keygen \
- -t ed25519 \
- -f "/root/.ssh/id_ed25519" -q -N "" \
- -C "$(date +%Y%m%d)-root@$(hostname -b)" \
- && cat "/root/.ssh/id_ed25519.pub")
+ && return 0
echo
- echo "Now you have to register the public ssh-key from above into your git-server to grant these access rights:"
+ echo "FAILED: somthing went wrong during the generation the ssh keys."
+ echo " These keys are mandantory. You can try to restart this script."
+ echo
+}
+
+function showFurtherSteps() {}
+ echo
+ echo "IMPORTANT: It is assumed that repositories for definitions and states already exist"
+ echo " and comply with the naming convention."
+ echo " Otherwise, these repositories must be created first!"
+ echo
+ echo "To grant the correct access rights, you have to register the above-mentioned ssh key,"
+ echo "as deploy key in these repositories of the Git server:"
echo " - scripts repository (allow readonly access only),"
echo " - definitions repository (allow readonly access only),"
echo " - states repository (allow writable access)."
echo
- echo "After all access rights are granted you can clone the Infrastructure System:"
- echo " e.g.: git clone ssh://git@git.example.dev:22448/iss.git /iss"
+ echo "After all access rights are granted you can clone the Core Infrastructure System:"
+ echo " e.g.: git clone ssh://git@git.example.dev:22448/cis.git /cis"
echo
- echo "Finally call 'setupCoreOntoThisHost.sh' from the root directory of the repository:"
- echo " e.g.: /iss/setupCoreOntoThisHost.sh"
+ echo "Finally call 'setupCoreOntoThisHost.sh' from the root directory:"
+ echo " e.g.: /cis/setupCoreOntoThisHost.sh"
echo
}
# sanitizes all parameters
setNeededHostnameOrExit "$(echo ${1} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
- && prepare
+ && prepareThisHost \
+ && showFurtherSteps \
+ && exit 0
+
+exit 1
diff --git a/setupCoreOntoThisHost.sh b/setupCoreOntoThisHost.sh
index f745839..c7e5d82 100755
--- a/setupCoreOntoThisHost.sh
+++ b/setupCoreOntoThisHost.sh
@@ -6,6 +6,12 @@
+# Folders always ends with an tailing '/'
+_SETUP="$(readlink -f "${0}" 2> /dev/null)"
+_CIS_ROOT="${_SETUP%/setupCoreOntoThisHost.sh}/" #Removes shortest matching pattern '/setupCoreOntoThisHost.sh' from the end
+_CORE_SCRIPTS="${_CIS_ROOT:?"Missing CIS_ROOT"}core/"
+
+
function checkPathsAreAvaiable() {
grep --version &> /dev/null \
@@ -31,22 +37,21 @@ function checkGitIsAvailable() {
}
function checkPreconditions() {
- local _ROOT _DOMAIN
- _ROOT="${1:?"Missing parameter ROOT"}"
- _DOMAIN="${2}" # Optional parameter DOMAIN
- readonly _ROOT _DOMAIN
+ local _DOMAIN
+ _DOMAIN="${1}" # Optional parameter DOMAIN
+ readonly _DOMAIN
! [ -z "${_DOMAIN}" ] \
&& [ "$(hostname -d)" != "${_DOMAIN}" ] \
&& echo \
- && echo "WARNING: system-domain DOES NOT MATCH domainOfHostOwner: '$(hostname -d)' != '${_DOMAIN}'" \
+ && echo "WARNING: system-domain DOES NOT MATCH overrideOwnDomain: '$(hostname -d)' != '${_DOMAIN}'" \
&& echo
# Given domain verfügbar (nicht leer)
! [ -z "${_DOMAIN}" ] \
&& checkPathsAreAvaiable \
&& checkGitIsAvailable \
- && git -C "${_ROOT}" pull &> /dev/null \
+ && git -C "${_CIS_ROOT:?"Missing CIS_ROOT"}" pull &> /dev/null \
&& return 0
echo
@@ -69,63 +74,65 @@ function checkPreconditions() {
}
function getOrSetDomain() {
- local _ROOT _DOMAIN_FILE _GIVEN_DOMAIN
- _ROOT="${1:?"Missing parameter ROOT"}"
- _DOMAIN_FILE="${_ROOT:?"Missing ROOT"}domainOfHostOwner"
- _GIVEN_DOMAIN="${2}" # Optional parameter DOMAIN
- readonly _ROOT _DOMAIN_FILE _GIVEN_DOMAIN
+ local _CURRENT_DOMAIN _GIVEN_DOMAIN _OVERRIDE_DOMAIN_FILE
+ _CURRENT_DOMAIN="$("${_CORE_SCRIPTS:?"Missing CORE_SCRIPTS"}printOwnDomain.sh")"
+ _GIVEN_DOMAIN="${1}" # Optional parameter DOMAIN
+ _OVERRIDE_DOMAIN_FILE="${_CIS_ROOT:?"Missing CIS_ROOT"}overrideOwnDomain"
+ readonly _CURRENT_DOMAIN _GIVEN_DOMAIN _OVERRIDE_DOMAIN_FILE
- # Wenn DOMAIN_FILE enhält lesbare Daten
- grep '[^[:space:]]' "${_DOMAIN_FILE:?"Missing DOMAIN_FILE"}" &> /dev/null \
- && cat "${_DOMAIN_FILE}" \
+ ! [ -z "${_CURRENT_DOMAIN}" ] \
+ && [ -z "${_GIVEN_DOMAIN}" ] \
+ && echo "${_CURRENT_DOMAIN}" \
&& return 0
- # Der boot-hostname muss mindestens einen Punkt enthalten, dann wird die hintere Hälfte als Domain genommen
- hostname -b | grep "\." | cut -d. -f2- > "${_DOMAIN_FILE}"
- grep '[^[:space:]]' "${_DOMAIN_FILE}" &> /dev/null \
- && cat "${_DOMAIN_FILE}" \
+ ! [ -z "${_CURRENT_DOMAIN}" ] \
+ && [ "${_CURRENT_DOMAIN}" == "${_GIVEN_DOMAIN}" ] \
+ && echo "${_CURRENT_DOMAIN}" \
&& return 0
- # Given domain is set (nicht leer)
- ! [ -z "${_GIVEN_DOMAIN}" ] \
+ # If there is a given domain it will be set or it will override the current one
+ [ -z "${_CURRENT_DOMAIN}" ] \
+ && ! [ -z "${_GIVEN_DOMAIN}" ] \
&& [ "$(id -u)" == "0" ] \
+ && echo "Setting hostname to: $(hostname -s).${_GIVEN_DOMAIN}" >&2 \
&& hostnamectl set-hostname "$(hostname -s).${_GIVEN_DOMAIN}" \
- && hostname -b | grep "\." | cut -d. -f2- > "${_DOMAIN_FILE}" \
- && grep '[^[:space:]]' "${_DOMAIN_FILE}" &> /dev/null \
- && cat "${_DOMAIN_FILE}" \
+ && echo "${_GIVEN_DOMAIN}" \
+ && return 0
+
+ ! [ -z "${_GIVEN_DOMAIN}" ] \
+ && echo "Overwriting domain to: ${_GIVEN_DOMAIN}" >&2 \
+ && echo "${_GIVEN_DOMAIN}" > "${_OVERRIDE_DOMAIN_FILE}" \
+ && echo "${_GIVEN_DOMAIN}" \
&& return 0
return 1
}
function getRemoteRepositoryPath() {
- local _ROOT
- _ROOT="${1:?"Missing parameter ROOT"}"
- readonly _ROOT
-
- _RESULT="$(git -C "${_ROOT:?"Missing ROOT"}" remote show origin | grep -i 'fetch' | xargs -n 1 | grep -i 'ssh://')"
- _RESULT="${_RESULT%/*}" #Removes shortest matching pattern '/*' from the end
- ! [ -z "${_RESULT}" ] \
- && echo "${_RESULT}" \
+ _REPOSITORY="$(git -C "${_CIS_ROOT:?"Missing CIS_ROOT"}" config --get remote.origin.url 2> /dev/null | grep -i 'git@')"
+ _PATH="${_REPOSITORY%/*}" #Removes shortest matching pattern '/*' from the end
+ ! [ -z "${_PATH}" ] \
+ && echo "${_PATH}/" \
&& return 0
return 1
}
function addDefinition(){
- local _ROOT _CORE_SCRIPTS _DEFINITIONS _REPOSITORY
- _DEFINITIONS="${1:?"Missing parameter DEFINITIONS"}"
- _REPOSITORY="${2:?"Missing parameter REPOSITORY"}"
- _ROOT="${_DEFINITIONS%%/definitions/*}/" #Removes longest matching pattern '/definitions/*' from the end
- _CORE_SCRIPTS="${_ROOT:?"Missing ROOT"}core/"
- readonly _ROOT _CORE_SCRIPTS _DEFINITIONS _REPOSITORY
+ local _DEFINITIONS _REPOSITORY
+ _DEFINITIONS="${1:?"Missing first parameter DEFINITIONS"}"
+ _REPOSITORY="$(getRemoteRepositoryPath)cis-definition-${2:?"Missing second parameter DOMAIN"}.git"
+ readonly _DEFINITIONS _REPOSITORY
+
[ "$(id -u)" == "0" ] \
- && "${_CORE_SCRIPTS:?"Missing CORE_SCRIPTS"}addAndCheckGitRepository.sh" "${_DEFINITIONS}" "${_REPOSITORY}" readonly \
+ && echo "Running setup as 'root' trying to add definition repository:" \
+ && "${_CORE_SCRIPTS:?"Missing CORE_SCRIPTS"}addAndCheckGitRepository.sh" "${_DEFINITIONS}" readonly "${_REPOSITORY}" \
&& echo " - definitions are usable for this host." \
&& return 0
[ "$(id -u)" != "0" ] \
- && "${_CORE_SCRIPTS:?"Missing CORE_SCRIPTS"}addAndCheckGitRepository.sh" "${_DEFINITIONS}" "${_REPOSITORY}" writable \
+ && echo "Running setup as 'user' trying to add definition repository:" \
+ && "${_CORE_SCRIPTS:?"Missing CORE_SCRIPTS"}addAndCheckGitRepository.sh" "${_DEFINITIONS}" writable "${_REPOSITORY}" \
&& echo " - definitions are usable, as working copy." \
&& return 0
@@ -133,20 +140,22 @@ function addDefinition(){
}
function addState() {
- local _ROOT _CORE_SCRIPTS _STATES _REPOSITORY
- _STATES="${1:?"Missing parameter STATES"}"
- _REPOSITORY="${2:?"Missing parameter REPOSITORY"}"
- _ROOT="${_STATES%%/states/*}/" #Removes longest matching pattern '/states/*' from the end
- _CORE_SCRIPTS="${_ROOT:?"Missing ROOT"}core/"
- readonly _ROOT _CORE_SCRIPTS _STATES _REPOSITORY
+ local _STATES _REPOSITORY
+ _STATES="${1:?"Missing first parameter STATES"}"
+ _REPOSITORY="$(getRemoteRepositoryPath)cis-state-${2:?"Missing second parameter DOMAIN"}.git"
+ readonly _STATES _REPOSITORY
[ "$(id -u)" == "0" ] \
- && "${_CORE_SCRIPTS:?"Missing CORE_SCRIPTS"}addAndCheckGitRepository.sh" "${_STATES}" "${_REPOSITORY}" writable \
+ && echo "Running setup as 'root' trying to add state repository:" \
+ && echo \
+ && "${_CORE_SCRIPTS:?"Missing CORE_SCRIPTS"}addAndCheckGitRepository.sh" "${_STATES}" writable "${_REPOSITORY}" \
&& echo " - states are usable for this host." \
&& return 0
[ "$(id -u)" != "0" ] \
- && "${_CORE_SCRIPTS:?"Missing CORE_SCRIPTS"}addAndCheckGitRepository.sh" "${_STATES}" "${_REPOSITORY}" writable \
+ && echo "Running setup as 'user' trying to add state repository:" \
+ && echo \
+ && "${_CORE_SCRIPTS:?"Missing CORE_SCRIPTS"}addAndCheckGitRepository.sh" "${_STATES}" writable "${_REPOSITORY}" \
&& echo " - states are usable, as working copy." \
&& return 0
@@ -154,13 +163,10 @@ function addState() {
}
function setupCoreFunctionality() {
- local _ROOT _CORE_SCRIPTS _DEFINITIONS _MINUTE_FROM_OWN_IP _SETUP
+ local _DEFINITIONS _MINUTE_FROM_OWN_IP
_DEFINITIONS="${1:?"Missing DEFINITIONS: 'ROOT/definitions/DOMAIN'"}"
- _ROOT="${_DEFINITIONS%%/definitions/*}/" #Removes longest matching pattern '/definitions/*' from the end
- _CORE_SCRIPTS="${_ROOT:?"Missing ROOT"}core/"
- _MINUTE_FROM_OWN_IP="$(hostname -I | xargs -n 1 | grep -F . | head -n 1 | cut -d. -f4 || echo 0)" #uses last value from first own ipv4 or 0 as minute value
- _SETUP="${2:?"Missing SETUP"}"
- readonly _ROOT _CORE_SCRIPTS _DEFINITIONS _MINUTE_FROM_OWN_IP _SETUP
+ _MINUTE_FROM_OWN_IP="$(hostname -I | xargs -n 1 | grep -F '.' | head -n 1 | cut -d. -f4 || echo 0)" #uses last value from first own ipv4 or 0 as minute value
+ readonly _DEFINITIONS _MINUTE_FROM_OWN_IP
[ "$(id -u)" != "0" ] \
&& echo "Configuration of host skipped because of insufficient rights." \
@@ -176,45 +182,39 @@ function setupCoreFunctionality() {
&& echo \
&& "${_CORE_SCRIPTS:?"Missing CORE_SCRIPTS"}ensureUsageOfDefinitions.sh" "${_DEFINITIONS}" /etc/sudoers.d/allow-jenkins-updateRepositories \
&& echo \
- && "${_CORE_SCRIPTS:?"Missing CORE_SCRIPTS"}addToCrontabEveryHour.sh" "${_SETUP}" "${_MINUTE_FROM_OWN_IP}" \
+ && "${_CORE_SCRIPTS:?"Missing CORE_SCRIPTS"}addToCrontabEveryHour.sh" "${_SETUP:?"Missing SETUP"}" "${_MINUTE_FROM_OWN_IP}" \
&& return 0
return 1
}
function setup() {
- local _ROOT _DEFINITIONS _DEFINITIONS_REPOSITORY _DOMAIN _REPOSITORY_PATH _SETUP _STATES _STATES_REPOSITORY
- _SETUP="$(readlink -f "${0}" 2> /dev/null)"
- _ROOT="$(dirname ${_SETUP:?"Missing SETUP"} 2> /dev/null || echo "/iss")/"
- _DOMAIN="$(getOrSetDomain "${_ROOT:?"Missing ROOT"}" "${1}")"
- _REPOSITORY_PATH="$(getRemoteRepositoryPath "${_ROOT:?"Missing ROOT"}")"
+ local _DEFINITIONS _DOMAIN _STATES
+ _DOMAIN="$(getOrSetDomain "${1}")"
- ! checkPreconditions "${_ROOT:?"Missing ROOT"}" "${_DOMAIN}" \
+ ! checkPreconditions "${_DOMAIN}" \
&& return 1
- _DEFINITIONS="${_ROOT:?"Missing ROOT"}definitions/${_DOMAIN:?"Missing DOMAIN"}"
- _DEFINITIONS_REPOSITORY="${_REPOSITORY_PATH:?"Missing REPOSITORY_PATH"}/iss-definition-${_DOMAIN:?"Missing DOMAIN"}.git"
- _STATES="${_ROOT:?"Missing ROOT"}states/${_DOMAIN:?"Missing DOMAIN"}"
- _STATES_REPOSITORY="${_REPOSITORY_PATH:?"Missing REPOSITORY_PATH"}/iss-state-${_DOMAIN:?"Missing DOMAIN"}.git"
- readonly _ROOT _DEFINITIONS _DEFINITIONS_REPOSITORY _DOMAIN _REPOSITORY_PATH _SETUP _STATES _STATES_REPOSITORY
+ _DEFINITIONS="${_CIS_ROOT:?"Missing CIS_ROOT"}definitions/${_DOMAIN:?"Missing DOMAIN"}"
+ _STATES="${_CIS_ROOT:?"Missing CIS_ROOT"}states/${_DOMAIN:?"Missing DOMAIN"}"
+ readonly _DEFINITIONS _DOMAIN _STATES
echo \
- && echo "Running setup using repositories of: '${_REPOSITORY_PATH:?"Missing REPOSITORY_PATH"}' ..." \
+ && addDefinition "${_DEFINITIONS:?"Missing DEFINITIONS"}" "${_DOMAIN:?"Missing DOMAIN"}" \
&& echo \
- && addDefinition "${_DEFINITIONS:?"Missing DEFINITIONS"}" "${_DEFINITIONS_REPOSITORY:?"Missing DEFINITIONS_REPOSITORY"}" \
- && echo \
- && addState "${_STATES:?"Missing STATES"}" "${_STATES_REPOSITORY:?"Missing STATES_REPOSITORY"}" \
+ && addState "${_STATES:?"Missing STATES"}" "${_DOMAIN:?"Missing DOMAIN"}" \
&& echo \
&& echo "Using definitions: '${_DEFINITIONS:?"Missing DEFINITIONS"}' ..." \
- && setupCoreFunctionality "${_DEFINITIONS:?"Missing DEFINITIONS"}" "${_SETUP:?"Missing SETUP"}" \
+ && setupCoreFunctionality "${_DEFINITIONS:?"Missing DEFINITIONS"}" \
&& return 0
- echo "FAIL: setup is incomplete: ("$(readlink -f ${0})")"
- echo " - due to an error or insufficient rights."
+ echo "FAIL: setup is incomplete: ("$(readlink -f ${0})")" >&2
+ echo " - due to an error or insufficient rights." >&2
return 1
}
# sanitizes all parameters
-setup \
- "$(echo ${1} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
- && exit 0 || exit 1
+setup "$(echo ${1} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
+ && exit 0
+
+exit 1
diff --git a/updateRepositories.sh b/updateRepositories.sh
index cf6c13e..bbad32e 100755
--- a/updateRepositories.sh
+++ b/updateRepositories.sh
@@ -20,54 +20,61 @@
function update_repositories() {
- local _ROOT _DEFINITIONS _DOMAIN _MODE _STATES _UPDATE_REPOSITORIES
+ local _CIS_ROOT _DEFINITIONS _DOMAIN _MODE _STATES _UPDATE_REPOSITORIES
_UPDATE_REPOSITORIES="$(readlink -f "${0}" 2> /dev/null)"
- _MODE="${1:-"all"}"
- _ROOT="$(dirname ${_UPDATE_REPOSITORIES:?"Missing UPDATE_REPOSITORIES"} 2> /dev/null || echo "/iss")/"
- _DOMAIN="$(cat ${_ROOT:?"Missing ROOT"}domainOfHostOwner)"
- _DEFINITIONS="${_ROOT}definitions/${_DOMAIN:?"Missing DOMAIN from file: ${_ROOT}domainOfHostOwner"}/"
- _STATES="${_ROOT}states/${_DOMAIN:?"Missing DOMAIN from file: ${_ROOT}domainOfHostOwner"}/"
- readonly _ROOT _DEFINITIONS _DOMAIN _MODE _STATES _UPDATE_REPOSITORIES
+ _CIS_ROOT="${_UPDATE_REPOSITORIES%/updateRepositories.sh}/" #Removes shortest matching pattern '/updateRepositories.sh' from the end
+ _MODE="${1:-"--core"}"
+ _DOMAIN="$(${_CIS_ROOT:?"Missing CIS_ROOT"}core/printOwnDomain.sh)"
+ _DEFINITIONS="${_CIS_ROOT}definitions/${_DOMAIN:?"Missing DOMAIN from file: ${_CIS_ROOT}domainOfHostOwner"}/"
+ _STATES="${_CIS_ROOT}states/${_DOMAIN:?"Missing DOMAIN from file: ${_CIS_ROOT}domainOfHostOwner"}/"
+ readonly _CIS_ROOT _DEFINITIONS _DOMAIN _MODE _STATES _UPDATE_REPOSITORIES
[ "${_MODE}" == "--repair" ] \
- && (git -C "${_ROOT}" reset --hard origin/master; \
- git -C "${_DEFINITIONS}" reset --hard origin/master; \
- git -C "${_STATES}" reset --hard origin/master; \
+ && (git -C "${_CIS_ROOT}" reset --hard origin/main; \
+ git -C "${_DEFINITIONS}" reset --hard origin/main; \
+ git -C "${_STATES}" reset --hard origin/main; \
echo "Run repairs") \
&& return 0
[ "${_MODE}" == "--test" ] \
- && git -C "${_ROOT}" pull \
+ && git -C "${_CIS_ROOT}" pull \
&& git -C "${_DEFINITIONS}" pull \
&& git -C "${_STATES}" pull \
&& echo "Run in testMode successfully." \
&& return 0
[ "${_MODE}" == "--scripts" ] \
- && echo "Host $HOSTNAME updating scripts: ${_ROOT} ..." \
- && (git -C "${_ROOT}" pull &> /dev/null &) \
+ && printf "Host $HOSTNAME updating scripts: ${_CIS_ROOT} ... " \
+ && (git -C "${_CIS_ROOT}" pull &> /dev/null) \
+ && echo "(done)" \
&& return 0
[ "${_MODE}" == "--definitions" ] \
- && echo "Host ${HOSTNAME} updating definitions: ${_DEFINITIONS} ..." \
- && (git -C "${_DEFINITIONS}" pull &> /dev/null &) \
+ && echo "Host ${HOSTNAME} updating definitions: ${_DEFINITIONS} ... " \
+ && (git -C "${_DEFINITIONS}" pull &> /dev/null) \
+ && echo "(done)" \
&& return 0
[ "${_MODE}" == "--states" ] \
- && echo "Host ${HOSTNAME} updating states: ${_STATES} ..." \
- && (git -C "${_STATES}" pull &> /dev/null &) \
+ && echo "Host ${HOSTNAME} updating states: ${_STATES} ... " \
+ && (git -C "${_STATES}" pull &> /dev/null) \
+ && echo "(done)" \
&& return 0
- echo "Host ${HOSTNAME} updating ${_MODE}:" \
- && echo " - ${_ROOT}" \
- && echo " - ${_DEFINITIONS}" \
- && echo " - ${_STATES}"
- git -C "${_ROOT}" pull &> /dev/null
- git -C "${_DEFINITIONS}" pull &> /dev/null
- git -C "${_STATES}" pull &> /dev/null
+ [ "${_MODE}" == "--core" ] \
+ && echo "Host ${HOSTNAME} updating core including scripts, definitions and states: ${_STATES} ... " \
+ && (git -C "${_CIS_ROOT}" pull &> /dev/null) \
+ && (git -C "${_DEFINITIONS}" pull &> /dev/null) \
+ && (git -C "${_STATES}" pull &> /dev/null) \
+ && echo "(done)" \
+ && return 0
+
+ echo "FAILED: an error occurred during an update."
+ return 1
}
# sanitizes all parameters
-update_repositories \
- "$(echo ${1} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
- && exit 0 || exit 1
+update_repositories "$(echo ${1} | sed -E 's|[^a-zA-Z0-9/:@._-]*||g')" \
+ && exit 0
+
+exit 1