Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
centos:ansible:first [14.01.2020 16:19. ] – [Zielverzeichnis anlegen und öffentlichen Schlüssel kopieren] django | centos:ansible:first [14.09.2022 11:46. ] (aktuell) – Seite in neuen Namensraum verschoben django | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | ====== Erste Schritte Rund um Ansible ====== | ||
- | {{: | ||
- | Nachdem wir uns bereits eingehend mit den **[[centos: | ||
- | |||
- | ===== Voraussetzung: | ||
- | Einer der wesentlichen Vorteil von Ansible ist, dass hierzu kein separater eigener Server aufgesetzt werden muss, sondern dass im Grunde ein (Client-/ | ||
- | |||
- | ==== Dokumentation ==== | ||
- | Wichtige Hinweise zu Sicherheitsthemen rund um **SSH** finden sich im [[https:// | ||
- | |||
- | ==== SSH-Schlüssel erstellen ==== | ||
- | Damit sich nun unser Ansible-Admin-Host auch Verbindungen mit Hilfe der **SSH**((**S**ecure** SH**ell)) aufbauen kann, benötigen wir natürlich entsprechendes Schlüsselmaterial, | ||
- | === RSA-Schlüssel === | ||
- | Im ersten Fall erstellen wir uns einen **RSA**-Schlüssel (**'' | ||
- | $ ssh-keygen -b 4096 -t rsa -C ' | ||
- | |||
- | < | ||
- | Enter passphrase (empty for no passphrase): | ||
- | Enter same passphrase again: | ||
- | Your identification has been saved in / | ||
- | Your public key has been saved in / | ||
- | The key fingerprint is: | ||
- | SHA256: | ||
- | The key's randomart image is: | ||
- | +---[RSA 4096]----+ | ||
- | |+++E. | ||
- | |+.+o o + | | ||
- | |o= .o + = | | ||
- | |..+ * + . | | ||
- | |o . o + S = | | ||
- | |.= o + o o . | | ||
- | |= o. + | ||
- | |B+o . .. . | | ||
- | |o=+. ... .. | | ||
- | +----[SHA256]-----+ | ||
- | </ | ||
- | |||
- | === ED25519-Schlüssel === | ||
- | <WRAP center round important 90%> | ||
- | Ob man in Zeiten von Überwachungsphantasten in Unternehmen und vor allem auch bei einer NSA oder BND, noch solchen **[[http:// | ||
- | |||
- | Der Sicherheitsguru Bruce Schneier hat in seinem **[[https:// | ||
- | |||
- | <wrap em>//" | ||
- | </ | ||
- | |||
- | Auf diese RSA-Schlüssel muss man aber nicht mehr zwingend zurückgreifen, | ||
- | |||
- | Im zweiten Fall erstellen wir uns nun einen **ED25519**-Schlüssel (**'' | ||
- | $ ssh-keygen -t ed25519 -a 100 -C ' | ||
- | |||
- | < | ||
- | Enter passphrase (empty for no passphrase): | ||
- | Enter same passphrase again: | ||
- | Your identification has been saved in / | ||
- | Your public key has been saved in / | ||
- | The key fingerprint is: | ||
- | SHA256: | ||
- | The key's randomart image is: | ||
- | +--[ED25519 256]--+ | ||
- | | | ||
- | | .E+ +.+. | | ||
- | | ++.. = * | | ||
- | | +..+ + O . | | ||
- | | | ||
- | | ... o * . | | ||
- | | .oo o + + .| | ||
- | | .... o . = | | ||
- | | | ||
- | +----[SHA256]-----</ | ||
- | |||
- | ==== Zielverzeichnis anlegen und öffentlichen Schlüssel kopieren ==== | ||
- | Hat man die Struktur, wie i.d.R. öffentliche Schlüssel auf einem Zielsystem bereits verinnerlicht, | ||
- | |||
- | Auf dem den Zielrechnern legen wir nun das Verzeichnis **.ssh** an und schützen es entsprechend. | ||
- | |||
- | [django@zielhost django]$ (umask 077 ; mkdir -p $HOME/.ssh) | ||
- | |||
- | Den öffentlichen Schlüssel kopieren wir dann wie folgt auf das Zielsystem; hatten wir uns einen RSA-key erstellt verwenden wir folgenden Aufruf: | ||
- | | ||
- | bzw. bei einem ed25519 Schlüssel: | ||
- | | ||
- | |||
- | Anschließend wird der Schlüssel in die Datei authorized_keys kopiert. Diese Datei kann mehrere Schlüssel enthalten, daher ist das doppelte Umleitungszeichen wichtig, um eine evt. existierende Datei nicht versehentlich zu überschreiben. Somit wird der neue Schlüssel in die Datei hinzugefügt: | ||
- | $ cat key.pub >> authorized_keys | ||
- | |||
- | Zu guter Letzt passen wir noch die Berechtigungen an und löschen die nicht mehr benötigten Public-key-Datei. | ||
- | $ chmod 600 authorized_keys | ||
- | $ rm key.pub | ||
- | |||
- | |||
- | <WRAP round info> | ||
- | Das Kopieren des Public-Keys auf unseren Zielhost mit Anpassen der Dateiberechtigungen kann man natürlich auch einfacher vornehmen. Man benutzt hierzu einfach den Befehl **ssh-copy-id** aus dem Paket // | ||
- | |||
- | * RSA-Key < | ||
- | * ed25519-Key < | ||
- | |||
- | Mit der Angabe '' | ||
- | </ | ||
- | |||
- | ==== Verbindungstest via SSH ==== | ||
- | Nun können wir eine erste Testverbindung zu unserem Zielsystem aufbauen. | ||
- | $ ssh -l ansible -i ~/ | ||
- | < | ||
- | # # | ||
- | # ╭∩╮( ͡° ل͟ ͡° )╭∩╮ | ||
- | # # | ||
- | # | ||
- | # # | ||
- | # This system is actively monitored and all connections may be logged. | ||
- | # By accessing this system, you consent to this monitoring. | ||
- | # # | ||
- | ############################################################################## | ||
- | Activate the web console with: systemctl enable --now cockpit.socket | ||
- | |||
- | Last login: Mon Dec 30 21:43:35 2019</ | ||
- | |||
- | ===== (Grund-)Konfiguration ===== | ||
- | Die Konfigurationsdateien rund um Ansible finden sich im Verzeichnis **''/ | ||
- | < | ||
- | ├── ansible.cfg | ||
- | ├── hosts | ||
- | └── roles | ||
- | </ | ||
- | |||
- | ==== / | ||
- | Fast alle Parameter können in einem Ansible-playbook oder mit Kommandozeilenflags überschrieben werden. Ansible liest ANSIBLE_CONFIG, | ||
- | # vim / | ||
- | |||
- | <file bash / | ||
- | # =============================================== | ||
- | |||
- | # nearly all parameters can be overridden in ansible-playbook | ||
- | # or with command line flags. ansible will read ANSIBLE_CONFIG, | ||
- | # ansible.cfg in the current working directory, .ansible.cfg in | ||
- | # the home directory or / | ||
- | # finds first | ||
- | |||
- | [defaults] | ||
- | |||
- | # some basic default values... | ||
- | |||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | |||
- | # plays will gather facts by default, which contain information about | ||
- | # the remote system. | ||
- | # | ||
- | # smart - gather by default, but don't regather if already gathered | ||
- | # implicit - gather by default, turn off with gather_facts: | ||
- | # explicit - do not gather by default, must say gather_facts: | ||
- | #gathering = implicit | ||
- | |||
- | # This only affects the gathering done by a play's gather_facts directive, | ||
- | # by default gathering retrieves all facts subsets | ||
- | # all - gather all subsets | ||
- | # network - gather min and network facts | ||
- | # hardware - gather hardware facts (longest facts to retrieve) | ||
- | # virtual - gather min and virtual facts | ||
- | # facter - import facts from facter | ||
- | # ohai - import facts from ohai | ||
- | # You can combine them using comma (ex: network, | ||
- | # You can negate them using ! (ex: !hardware, | ||
- | # A minimal set of facts is always gathered. | ||
- | # | ||
- | |||
- | # some hardware related facts are collected | ||
- | # with a maximum timeout of 10 seconds. This | ||
- | # option lets you increase or decrease that | ||
- | # timeout to something more suitable for the | ||
- | # environment. | ||
- | # gather_timeout = 10 | ||
- | |||
- | # Ansible facts are available inside the ansible_facts.* dictionary | ||
- | # namespace. This setting maintains the behaviour which was the default prior | ||
- | # to 2.5, duplicating these variables into the main namespace, each with a | ||
- | # prefix of ' | ||
- | # This variable is set to True by default for backwards compatibility. It | ||
- | # will be changed to a default of ' | ||
- | # ansible_facts. | ||
- | # inject_facts_as_vars = True | ||
- | |||
- | # additional paths to search for roles in, colon separated | ||
- | # | ||
- | |||
- | # uncomment this to disable SSH key host checking | ||
- | # | ||
- | |||
- | # change the default callback, you can only have one ' | ||
- | # | ||
- | |||
- | |||
- | ## Ansible ships with some plugins that require whitelisting, | ||
- | ## this is done to avoid running all of a type by default. | ||
- | ## These setting lists those that you want enabled for your system. | ||
- | ## Custom plugins should not need this unless plugin author specifies it. | ||
- | |||
- | # enable callback plugins, they can output to stdout but cannot be ' | ||
- | # | ||
- | |||
- | # Determine whether includes in tasks and handlers are " | ||
- | # default. As of 2.0, includes are dynamic by default. Setting these | ||
- | # values to True will make includes behave more like they did in the | ||
- | # 1.x versions. | ||
- | # | ||
- | # | ||
- | |||
- | # Controls if a missing handler for a notification event is an error or a warning | ||
- | # | ||
- | |||
- | # change this for alternative sudo implementations | ||
- | #sudo_exe = sudo | ||
- | |||
- | # What flags to pass to sudo | ||
- | # WARNING: leaving out the defaults might create unexpected behaviours | ||
- | #sudo_flags = -H -S -n | ||
- | |||
- | # SSH timeout | ||
- | #timeout = 10 | ||
- | |||
- | # default user to use for playbooks if user is not specified | ||
- | # (/ | ||
- | # | ||
- | |||
- | # logging is off by default unless this path is defined | ||
- | # if so defined, consider logrotate | ||
- | #log_path = / | ||
- | |||
- | # default module name for / | ||
- | # | ||
- | |||
- | # use this shell for commands executed under sudo | ||
- | # you may need to change this to bin/bash in rare instances | ||
- | # if sudo is constrained | ||
- | #executable = /bin/sh | ||
- | |||
- | # if inventory variables overlap, does the higher precedence one win | ||
- | # or are hash values merged together? | ||
- | # this can also be set to ' | ||
- | # | ||
- | |||
- | # by default, variables from roles will be visible in the global variable | ||
- | # scope. To prevent this, the following option can be enabled, and only | ||
- | # tasks and handlers within the role will see the variables there | ||
- | # | ||
- | |||
- | # list any Jinja2 extensions to enable here: | ||
- | # | ||
- | |||
- | # if set, always use this private key file for authentication, | ||
- | # if passing --private-key to ansible or ansible-playbook | ||
- | # | ||
- | |||
- | # If set, configures the path to the Vault password file as an alternative to | ||
- | # specifying --vault-password-file on the command line. | ||
- | # | ||
- | |||
- | # format of string {{ ansible_managed }} available within Jinja2 | ||
- | # templates indicates to users editing templates files will be replaced. | ||
- | # replacing {file}, {host} and {uid} and strftime codes with proper values. | ||
- | # | ||
- | # {file}, {host}, {uid}, and the timestamp can all interfere with idempotence | ||
- | # in some situations so the default is a static string: | ||
- | # | ||
- | |||
- | # by default, ansible-playbook will display " | ||
- | # should not be run on a host. Set this to " | ||
- | # messages. NOTE: the task header will still be shown regardless of whether or not the | ||
- | # task is skipped. | ||
- | # | ||
- | |||
- | # by default, if a task in a playbook does not include a name: field then | ||
- | # ansible-playbook will construct a header that includes the task's action but | ||
- | # not the task's args. This is a security feature because ansible cannot know | ||
- | # if the *module* considers an argument to be no_log at the time that the | ||
- | # header is printed. | ||
- | # stdout from ansible-playbook (or you have manually specified no_log in your | ||
- | # playbook on all of the tasks where you have secret information) then you can | ||
- | # safely set this to True to get more informative messages. | ||
- | # | ||
- | |||
- | # by default (as of 1.3), Ansible will raise errors when attempting to dereference | ||
- | # Jinja2 variables that are not set in templates or action lines. Uncomment this line | ||
- | # to revert the behavior to pre-1.3. | ||
- | # | ||
- | |||
- | # by default (as of 1.6), Ansible may display warnings based on the configuration of the | ||
- | # system running ansible itself. This may include warnings about 3rd party packages or | ||
- | # other conditions that should be resolved if possible. | ||
- | # to disable these warnings, set the following value to False: | ||
- | # | ||
- | |||
- | # by default (as of 1.4), Ansible may display deprecation warnings for language | ||
- | # features that should no longer be used and will be removed in future versions. | ||
- | # to disable these warnings, set the following value to False: | ||
- | # | ||
- | |||
- | # (as of 1.8), Ansible can optionally warn when usage of the shell and | ||
- | # command module appear to be simplified by using a default Ansible module | ||
- | # instead. | ||
- | # setting or adding warn=yes or warn=no to the end of the command line | ||
- | # parameter string. | ||
- | # instead of shelling out to the git command. | ||
- | # command_warnings = False | ||
- | |||
- | |||
- | # set plugin path directories here, separate with colons | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | |||
- | |||
- | # by default, ansible will use the ' | ||
- | # another one | ||
- | #strategy = free | ||
- | |||
- | # by default callbacks are not loaded for / | ||
- | # want, for example, a notification or logging callback to also apply to | ||
- | # / | ||
- | # | ||
- | |||
- | |||
- | # don't like cows? that's unfortunate. | ||
- | # set to 1 if you don't want cowsay support or export ANSIBLE_NOCOWS=1 | ||
- | #nocows = 1 | ||
- | |||
- | # set which cowsay stencil you'd like to use by default. When set to ' | ||
- | # a random stencil will be selected for each task. The selection will be filtered | ||
- | # against the `cow_whitelist` option below. | ||
- | # | ||
- | # | ||
- | |||
- | # when using the ' | ||
- | # it should be formatted as a comma-separated list with no spaces between names. | ||
- | # NOTE: line continuations here are for formatting purposes only, as the INI parser | ||
- | # in python does not support them. | ||
- | # | ||
- | # hellokitty, | ||
- | # stimpy, | ||
- | |||
- | # don't like colors either? | ||
- | # set to 1 if you don't want colors, or export ANSIBLE_NOCOLOR=1 | ||
- | #nocolor = 1 | ||
- | |||
- | # if set to a persistent type (not ' | ||
- | # from previous runs in Ansible will be stored. | ||
- | # wanting to use, for example, IP information from one group of servers | ||
- | # without having to talk to them in the same playbook run to get their | ||
- | # current IP information. | ||
- | # | ||
- | |||
- | #This option tells Ansible where to cache facts. The value is plugin dependent. | ||
- | #For the jsonfile plugin, it should be a path to a local directory. | ||
- | #For the redis plugin, the value is a host: | ||
- | |||
- | # | ||
- | |||
- | |||
- | |||
- | # retry files | ||
- | # When a playbook fails a .retry file can be created that will be placed in ~/ | ||
- | # You can enable this feature by setting retry_files_enabled to True | ||
- | # and you can change the location of the files by setting retry_files_save_path | ||
- | |||
- | # | ||
- | # | ||
- | |||
- | # squash actions | ||
- | # Ansible can optimise actions that call modules with list parameters | ||
- | # when looping. Instead of calling the module once per with_ item, the | ||
- | # module is called once with all items at once. Currently this only works | ||
- | # under limited circumstances, | ||
- | # | ||
- | |||
- | # prevents logging of task data, off by default | ||
- | #no_log = False | ||
- | |||
- | # prevents logging of tasks, but only on the targets, data is still logged on the master/ | ||
- | # | ||
- | |||
- | # controls whether Ansible will raise an error or warning if a task has no | ||
- | # choice but to create world readable temporary files to execute a module on | ||
- | # the remote machine. | ||
- | # turn this on to have behaviour more like Ansible prior to 2.1.x. | ||
- | # https:// | ||
- | # for more secure ways to fix this than enabling this option. | ||
- | # | ||
- | |||
- | # controls the compression level of variables sent to | ||
- | # worker processes. At the default of 0, no compression | ||
- | # is used. This value must be an integer from 0 to 9. | ||
- | # | ||
- | |||
- | # controls what compression method is used for new-style ansible modules when | ||
- | # they are sent to the remote system. | ||
- | # support compiled into both the controller' | ||
- | # The names should match with the python Zipfile compression types: | ||
- | # * ZIP_STORED (no compression. available everywhere) | ||
- | # * ZIP_DEFLATED (uses zlib, the default) | ||
- | # These values may be set per host via the ansible_module_compression inventory | ||
- | # variable | ||
- | # | ||
- | |||
- | # This controls the cutoff point (in bytes) on --diff for files | ||
- | # set to 0 for unlimited (RAM may suffer!). | ||
- | # | ||
- | |||
- | # This controls how ansible handles multiple --tags and --skip-tags arguments | ||
- | # on the CLI. If this is True then multiple arguments are merged together. | ||
- | # it is False, then the last specified argument is used and the others are ignored. | ||
- | # This option will be removed in 2.8. | ||
- | # | ||
- | |||
- | # Controls showing custom stats at the end, off by default | ||
- | # | ||
- | |||
- | # Controls which files to ignore when using a directory as inventory with | ||
- | # possibly multiple sources (both static and dynamic) | ||
- | # | ||
- | |||
- | # This family of modules use an alternative execution path optimized for network appliances | ||
- | # only update this setting if you know how this works, otherwise it can break module execution | ||
- | # | ||
- | |||
- | # When enabled, this option allows lookups (via variables like {{lookup(' | ||
- | # a loop with `with_foo`) to return data that is not marked " | ||
- | # jinja2 templating language which will be run through the templating engine. | ||
- | # ENABLING THIS COULD BE A SECURITY RISK | ||
- | # | ||
- | |||
- | # set default errors for all plays | ||
- | # | ||
- | |||
- | [inventory] | ||
- | # enable inventory plugins, default: ' | ||
- | # | ||
- | |||
- | # ignore these extensions when parsing a directory as inventory source | ||
- | # | ||
- | |||
- | # ignore files matching these patterns when parsing a directory as inventory source | ||
- | # | ||
- | |||
- | # If ' | ||
- | # | ||
- | |||
- | [privilege_escalation] | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | |||
- | [paramiko_connection] | ||
- | |||
- | # uncomment this line to cause the paramiko connection plugin to not record new host | ||
- | # keys encountered. | ||
- | # host key checking setting above. | ||
- | # | ||
- | |||
- | # by default, Ansible requests a pseudo-terminal for commands executed under sudo. Uncomment this | ||
- | # line to disable this behaviour. | ||
- | #pty=False | ||
- | |||
- | # paramiko will default to looking for SSH keys initially when trying to | ||
- | # authenticate to remote devices. | ||
- | # that close the connection after a key failure. | ||
- | # disable the Paramiko look for keys function | ||
- | # | ||
- | |||
- | # When using persistent connections with Paramiko, the connection runs in a | ||
- | # background process. | ||
- | # default Ansible will prompt to add the host key. This will cause connections | ||
- | # running in background processes to fail. Uncomment this line to have | ||
- | # Paramiko automatically add host keys. | ||
- | # | ||
- | |||
- | [ssh_connection] | ||
- | |||
- | # ssh arguments to use | ||
- | # Leaving off ControlPersist will result in poor performance, | ||
- | # paramiko on older platforms rather than removing it, -C controls compression use | ||
- | #ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s | ||
- | |||
- | # The base directory for the ControlPath sockets. | ||
- | # This is the " | ||
- | # | ||
- | # Example: | ||
- | # control_path_dir = / | ||
- | # | ||
- | |||
- | # The path to use for the ControlPath sockets. This defaults to a hashed string of the hostname, | ||
- | # port and username (empty string in the config). The hash mitigates a common problem users | ||
- | # found with long hostnames and the conventional %(directory)s/ | ||
- | # In those cases, a "too long for Unix domain socket" | ||
- | # | ||
- | # Example: | ||
- | # control_path = %(directory)s/ | ||
- | # | ||
- | |||
- | # Enabling pipelining reduces the number of SSH operations required to | ||
- | # execute a module on the remote server. This can result in a significant | ||
- | # performance improvement when enabled, however when using " | ||
- | # first disable ' | ||
- | # | ||
- | # By default, this option is disabled to preserve compatibility with | ||
- | # sudoers configurations that have requiretty (the default on many distros). | ||
- | # | ||
- | #pipelining = False | ||
- | |||
- | # Control the mechanism for transferring files (old) | ||
- | # * smart = try sftp and then try scp [default] | ||
- | # * True = use scp only | ||
- | # * False = use sftp only | ||
- | #scp_if_ssh = smart | ||
- | |||
- | # Control the mechanism for transferring files (new) | ||
- | # If set, this will override the scp_if_ssh option | ||
- | # * sftp = use sftp to transfer files | ||
- | # * scp = use scp to transfer files | ||
- | # * piped = use ' | ||
- | # * smart = try sftp, scp, and piped, in that order [default] | ||
- | # | ||
- | |||
- | # if False, sftp will not use batch mode to transfer files. This may cause some | ||
- | # types of file transfer failures impossible to catch however, and should | ||
- | # only be disabled if your sftp version has problems with batch mode | ||
- | # | ||
- | |||
- | # The -tt argument is passed to ssh when pipelining is not enabled because sudo | ||
- | # requires a tty by default. | ||
- | #usetty = True | ||
- | |||
- | # Number of times to retry an SSH connection to a host, in case of UNREACHABLE. | ||
- | # For each retry attempt, there is an exponential backoff, | ||
- | # so after the first attempt there is 1s wait, then 2s, 4s etc. up to 30s (max). | ||
- | #retries = 3 | ||
- | |||
- | [persistent_connection] | ||
- | |||
- | # Configures the persistent connection timeout value in seconds. | ||
- | # how long the persistent connection will remain idle before it is destroyed. | ||
- | # If the connection doesn' | ||
- | # expires, the connection is shutdown. The default value is 30 seconds. | ||
- | # | ||
- | |||
- | # The command timeout value defines the amount of time to wait for a command | ||
- | # or RPC call before timing out. The value for the command timeout must | ||
- | # be less than the value of the persistent connection idle timeout (connect_timeout) | ||
- | # The default value is 30 second. | ||
- | # | ||
- | |||
- | [accelerate] | ||
- | # | ||
- | # | ||
- | # | ||
- | |||
- | # The daemon timeout is measured in minutes. This time is measured | ||
- | # from the last activity to the accelerate daemon. | ||
- | # | ||
- | |||
- | # If set to yes, accelerate_multi_key will allow multiple | ||
- | # private keys to be uploaded to it, though each user must | ||
- | # have access to the system via SSH to add a new key. The default | ||
- | # is " | ||
- | # | ||
- | |||
- | [selinux] | ||
- | # file systems that require special treatment when dealing with security context | ||
- | # the default behaviour that copies the existing context or uses the user default | ||
- | # needs to be changed to use the file system dependent context. | ||
- | # | ||
- | |||
- | # Set this to yes to allow libvirt_lxc connections to work without SELinux. | ||
- | # | ||
- | |||
- | [colors] | ||
- | #highlight = white | ||
- | #verbose = blue | ||
- | #warn = bright purple | ||
- | #error = red | ||
- | #debug = dark gray | ||
- | #deprecate = purple | ||
- | #skip = cyan | ||
- | # | ||
- | #ok = green | ||
- | #changed = yellow | ||
- | #diff_add = green | ||
- | # | ||
- | #diff_lines = cyan | ||
- | |||
- | |||
- | [diff] | ||
- | # Always print diff when running ( same as always running with -D/--diff ) | ||
- | # always = no | ||
- | |||
- | # Set how many context lines to show in diff | ||
- | # context = 3 | ||
- | </ | ||
- | |||
- | {{page> | ||
- | |||
- | ==== Verbindungstest ==== | ||
- | Nachdem wir im Abschnitt **[# | ||
- | Dies können wir mit Hilfe des Folgenden SSH-Aufrufes bewerkstelligen: | ||
- | $ ssh -l ansible -i ~/ | ||
- | < | ||
- | # # | ||
- | # ╭∩╮( ͡° ل͟ ͡° )╭∩╮ | ||
- | # # | ||
- | # | ||
- | # # | ||
- | # This system is actively monitored and all connections may be logged. | ||
- | # By accessing this system, you consent to this monitoring. | ||
- | # # | ||
- | ############################################################################## | ||
- | total 16 | ||
- | drwx------. 3 ansible ansible | ||
- | drwxr-xr-x. 4 root root 35 Dec 30 21:43 ../ | ||
- | -rw-r--r--. 1 ansible ansible | ||
- | -rw-r--r--. 1 ansible ansible 141 Oct 1 15:26 .bash_profile | ||
- | -rw-r--r--. 1 ansible ansible 312 Oct 1 15:26 .bashrc | ||
- | drwx------. 2 ansible ansible | ||
- | -rw-------. 1 ansible ansible 793 Dec 30 21:47 .viminfo</ | ||
- | |||
- | Im Abschnitt **[[centos: | ||
- | $ ansible 10.0.0.90 -u ansible --private-key / | ||
- | |||
- | < | ||
- | <font style=" | ||
- | total 20 | ||
- | drwx------. 4 ansible ansible 127 Dec 30 22:26 ./ | ||
- | drwxr-xr-x. 4 root root 35 Dec 30 21:43 ../ | ||
- | drwx------. 3 ansible ansible | ||
- | -rw-------. 1 ansible ansible | ||
- | -rw-r--r--. 1 ansible ansible | ||
- | -rw-r--r--. 1 ansible ansible 141 Oct 1 15:26 .bash_profile | ||
- | -rw-r--r--. 1 ansible ansible 312 Oct 1 15:26 .bashrc | ||
- | drwx------. 2 ansible ansible | ||
- | -rw-------. 1 ansible ansible 793 Dec 30 21:47 .viminfo</ | ||
- | </ | ||
- | |||
- | Alternative dazu können wir natürlich auch den **Host** oder auch die definierten **Hostgruppen** aus unserer Konfigurationsdatei **''/ | ||
- | $ ansible centos_8 -u ansible --private-key / | ||
- | < | ||
- | <font style=" | ||
- | total 20 | ||
- | drwx------. 4 ansible ansible 127 Dec 30 22:26 ./ | ||
- | drwxr-xr-x. 4 root root 35 Dec 30 21:43 ../ | ||
- | drwx------. 3 ansible ansible | ||
- | -rw-------. 1 ansible ansible | ||
- | -rw-r--r--. 1 ansible ansible | ||
- | -rw-r--r--. 1 ansible ansible 141 Oct 1 15:26 .bash_profile | ||
- | -rw-r--r--. 1 ansible ansible 312 Oct 1 15:26 .bashrc | ||
- | drwx------. 2 ansible ansible | ||
- | -rw-------. 1 ansible ansible 793 Dec 30 21:47 .viminfo</ | ||
- | </ | ||
- | |||
- | Möchten wir testen, ob all unsere Hosts erreichbar sind, können wir z.B. nachfolgenden adhoc-Befehl verwenden: | ||
- | $ ansible all -u ansible --private-key / | ||
- | |||
- | < | ||
- | <font style=" | ||
- | " | ||
- | " | ||
- | " | ||
- | }</ | ||
- | <font style=" | ||
- | " | ||
- | " | ||
- | }, | ||
- | " | ||
- | " | ||
- | }</ | ||
- | </ | ||
- | |||
- | In dem gezeigten Fall ist der Host **bh7.dmz.nausch.org** aktuell nicht erreichbar und entsprechend **rot** gekennzeichnet. Der zweite **grün** markierte Host mit der IP-Adresse **10.0.0.90** hingegen ist erreichbar uns mit dem Zusatz **SUCCESS** versehen. | ||
- | |||
- | ===== erweiterte Konfiguration - Anpassungen ===== | ||
- | ==== remote User-Anpassung via ansible.conf ==== | ||
- | Um nun nicht bei jedem Aufruf den Remouteuser **'' | ||
- | |||
- | Wie öffnen also unsere Konfigurationsdatei und ergänzen nachfolgende Abschnitte. | ||
- | # vim / | ||
- | === remote_user === | ||
- | <code bash># default user to use for playbooks if user is not specified | ||
- | # (/ | ||
- | # | ||
- | # Django : 2019-12-30 | ||
- | remote_user = ansible | ||
- | </ | ||
- | |||
- | === private_key_file === | ||
- | <code bash># if set, always use this private key file for authentication, | ||
- | # if passing --private-key to ansible or ansible-playbook | ||
- | # | ||
- | # Django : 2019-12-30 | ||
- | private_key_file = / | ||
- | </ | ||
- | |||
- | === (Verbindungs-)Tests === | ||
- | Nun können wir schon mal viel einfacher ein [[centos: | ||
- | $ ansible centos_8 -m shell -a "/ | ||
- | < | ||
- | <font style=" | ||
- | CentOS Linux release 8.0.1905 (Core)</ | ||
- | </ | ||
- | |||
- | ==== remote User-Anpassung via Inventory hosts.yml ==== | ||
- | Das vorgenannte Beispiel funktioniert natürlich nur, wenn wir uns in einem homogenen Systemumfeld befinden, in dem alle Zielsysteme z.B. den gleichen Schlüsseltyp verwenden. Haben wir aber Systeme, die z.B. nur RSA-Schlüssel verwenden wie z.B. CentOS 6 Systeme oder Knoten eines Freifunk Netzes, so müssen wir natürlich eine Möglichkeit schaffen, für unterschiedliche Hosts auch unterschiedliche Schlüsseldateien und/oder sogar unterschiedliche User angeben zu können. | ||
- | |||
- | Wir verändern nun also unser Konfigurationsdatei **''/ | ||
- | |||
- | Wie öffnen also unsere Konfigurationsdatei und ergänzen nachfolgende Abschnitte. | ||
- | # vim / | ||
- | |||
- | === remote_user === | ||
- | Für unseren CentOS basierenden Hosts, bei denen wir den User **'' | ||
- | |||
- | <code bash># default user to use for playbooks if user is not specified | ||
- | # (/ | ||
- | # | ||
- | # Django : 2019-12-30 | ||
- | remote_user = ansible | ||
- | </ | ||
- | |||
- | === private_key_file === | ||
- | Den Eintrag für das keyfile für unseren vorherigen [[# | ||
- | |||
- | <code bash># if set, always use this private key file for authentication, | ||
- | # if passing --private-key to ansible or ansible-playbook | ||
- | # | ||
- | </ | ||
- | |||
- | === inventory === | ||
- | In der Konfigurationsdatei **'' | ||
- | |||
- | Wir hinterlegen also dort, dass zukünftig die Inventory-Datei **'' | ||
- | < | ||
- | |||
- | # some basic default values... | ||
- | |||
- | # Django : 2020-01-01 | ||
- | # default: # | ||
- | inventory | ||
- | </ | ||
- | |||
- | === hosts.yml === | ||
- | Unsere Hosts packen wir nun in der **[[centos: | ||
- | '' | ||
- | # vim / | ||
- | |||
- | <file bash / | ||
- | |||
- | centos8: | ||
- | hosts: | ||
- | | ||
- | | ||
- | | ||
- | # | ||
- | | ||
- | |||
- | centos7: | ||
- | hosts: | ||
- | | ||
- | | ||
- | | ||
- | # | ||
- | | ||
- | |||
- | ... #YAML end syntax | ||
- | </ | ||
- | |||
- | === (Verbindungs-)Tests === | ||
- | Nun können wir erneut ein [[centos: | ||
- | |||
- | Zunächst checken wir unser CentOS 7 System: | ||
- | $ ansible centos7 -m shell -a "/ | ||
- | < | ||
- | <font style=" | ||
- | CentOS Linux release 7.7.1908 (Core)</ | ||
- | </ | ||
- | |||
- | Anschließend überprüfen wir nun noch das CentOS 8 System: | ||
- | $ ansible centos8 -m shell -a "/ | ||
- | < | ||
- | <font style=" | ||
- | CentOS Linux release 8.0.1905 (Core)</ | ||
- | </ | ||
- | |||
- | ==== privilege_escalation ==== | ||
- | Wollen wir aber z.B. das Verzeichnis **''/ | ||
- | $ ansible centos_8 -m shell -a "/ | ||
- | < | ||
- | <font style=" | ||
- | / | ||
- | </ | ||
- | |||
- | === ohne Passwortabfrage === | ||
- | Wir müssen also nun dafür sorgen, dass die Befehle auf den Zielsystem mit den richtigen Rechten ausgeführt werden können. Hierzu passen wir nun die Konfigurationsdatei **''/ | ||
- | |||
- | < | ||
- | # Django : 2019-12-30 | ||
- | # default: unset | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | become=True | ||
- | become_method=sudo | ||
- | become_user=root | ||
- | become_ask_pass=False | ||
- | </ | ||
- | |||
- | Werden nun **root**-Rechte bei der Ausführung auf dem Remotesystem benötigt, werden diese | ||
- | * **'' | ||
- | * **'' | ||
- | * **'' | ||
- | * **'' | ||
- | |||
- | <WRAP center round alert 80%> | ||
- | **WICHTIG** : \\ \\ | ||
- | Auf einem Benutzerendgerät (Laptop, Desktop-Rechner) mag der geneigte sicherheitsbewusste Admin ja noch mit solch einer Rollen und Rechte-/ | ||
- | Ob man nun so eine Konfiguration auf einem Server, der unter Umständen noch dazu von mehreren Usern auf der Konsole genutzt werden kann, haben will, ist durchaus stark diskussionswürdig! | ||
- | |||
- | Sicher wird man da später bei der zentralen Konfiguration und Orchestrierung auf **[[# | ||
- | |||
- | </ | ||
- | |||
- | |||
- | Da unser Ansible-Systemuser **'' | ||
- | |||
- | $ ansible centos_8 -m shell -a "/ | ||
- | < | ||
- | <font style=" | ||
- | <font style=" | ||
- | total 44 | ||
- | dr-xr-x---. | ||
- | dr-xr-xr-x. 17 root root 224 Oct 21 14:12 ../ | ||
- | -rw-------. | ||
- | -rw-r--r--. | ||
- | -rw-r--r--. | ||
- | -rw-r--r--. | ||
- | drwx------. | ||
- | drwx------. | ||
- | -rw-r--r--. | ||
- | drwx------. | ||
- | -rw-r--r--. | ||
- | -rw-------. | ||
- | -rw-r--r--. | ||
- | -rw-------. | ||
- | </ | ||
- | |||
- | === mit Abfrage eines Passwortes === | ||
- | Dass eine Rechteerweiterung ohne Abfrage eines Passwortes nicht unbedingt erstrebenswert ist, wollen wir uns nun daran setzen unsere Konfiguration etwas optimieren. Aus Sicherheitsgründen wird ein user, sobald er mittels **'' | ||
- | |||
- | Unser Nutzer Ansible, den wir benutzen um per SSH auf die Zielsysteme zu gelangen, haben wir ja bereits in die Gruppe **'' | ||
- | # grep ansible /etc/group | ||
- | |||
- | wheel: | ||
- | ansible: | ||
- | |||
- | Der Eintrag **'' | ||
- | # egrep -v ' | ||
- | |||
- | %wheel ALL=(ALL) ALL | ||
- | |||
- | Nun passen wir nun die Konfigurationsdatei **''/ | ||
- | |||
- | < | ||
- | # Django : 2020-01-04 | ||
- | # default: unset | ||
- | # | ||
- | # | ||
- | # | ||
- | # | ||
- | become=True | ||
- | become_method=sudo | ||
- | become_user=root | ||
- | become_ask_pass=True | ||
- | </ | ||
- | |||
- | Werden nun **root**-Rechte bei der Ausführung auf dem Remotesystem benötigt, werden diese | ||
- | * **'' | ||
- | * **'' | ||
- | * **'' | ||
- | * **'' | ||
- | |||
- | Ohne die Anpassung müssten wir jedesmal beim Aufrudf des Befehls **'' | ||
- | |||
- | |||
- | Da unser Ansible-Systemuser **'' | ||
- | |||
- | $ ansible centos_8 -m shell -a "/ | ||
- | < | ||
- | <font style=" | ||
- | <font style=" | ||
- | total 44 | ||
- | dr-xr-x---. | ||
- | dr-xr-xr-x. 17 root root 224 Oct 21 14:12 ../ | ||
- | -rw-------. | ||
- | -rw-r--r--. | ||
- | -rw-r--r--. | ||
- | -rw-r--r--. | ||
- | drwx------. | ||
- | drwx------. | ||
- | -rw-r--r--. | ||
- | drwx------. | ||
- | -rw-r--r--. | ||
- | -rw-------. | ||
- | -rw-r--r--. | ||
- | -rw-------. | ||
- | </ | ||
- | \\ \\ | ||
- | <WRAP center round tip 80%> | ||
- | Neben der Ansicherung unseres SSH-Schlüssels mittel Passphrase habne wir auch unser Zielsystem nicht unnötig aufgeweicht. Und die einmalige Eingabe eines Passworts beim Befehl **'' | ||
- | </ | ||
- | |||
- | ===== Playbook - Beispiele ===== | ||
- | In den beiden Kapiteln **[[centos: | ||
- | |||
- | ==== Verzeichnis-Struktur ==== | ||
- | Für die weitere programmatische Arbeit legen wir uns am besten im Home-Verzeichnis unseres Admins ein Verzeichnis **'' | ||
- | # mkdir -p ~/ | ||
- | # mkdir -p ~/ | ||
- | |||
- | Somit haben wir folgende Struktur angelehgt: | ||
- | < | ||
- | ├── authkeys | ||
- | └── files</ | ||
- | |||
- | ==== 01: Benutzer anlegen ==== | ||
- | Bei unserem ersten Playbook-Beispiel wollen wir mit Hilfe von Ansible einen Benutzer auf unserem Zielsystem automatisiert anlegen. | ||
- | Bevor wir unser erstes Script schreiben, wechseln wir in unser zuvor angelegtes Zielverzeichnis: | ||
- | $ cd ~/ansible | ||
- | |||
- | === Script anlegen === | ||
- | Hier legen wir nun unser erstes Script ab. | ||
- | $ vim 01_create-user.yml | ||
- | |||
- | <file bash 01_create-user.yml> | ||
- | - hosts: centos8 | ||
- | become: true | ||
- | vars: | ||
- | sudoers: ansible | ||
- | createguid: ' | ||
- | createuser: ' | ||
- | createusername: | ||
- | createpassword: | ||
- | |||
- | tasks: | ||
- | - name: Make sure we have a group ' | ||
- | group: | ||
- | name: '{{ createuser }}' | ||
- | gid: '{{ createguid }}' | ||
- | state: present | ||
- | |||
- | - name: Add the user ' | ||
- | user: | ||
- | name: '{{ createuser }}' | ||
- | comment: '{{ createusername }}' | ||
- | uid: '{{ createguid }}' | ||
- | group: '{{ createuser }}' | ||
- | state: present | ||
- | |||
- | - name: Initial password generation for user ' | ||
- | shell: usermod -p $(echo '{{ createpassword }}' | openssl passwd -1 -stdin) {{ createuser }}</ | ||
- | |||
- | === Script Beschreibung === | ||
- | Die einzelnen Zeilen haben dabei folgende Funktionen und Aufgaben. | ||
- | Zeile: | ||
- | * Zeile **1**: **'' | ||
- | * Zeile **2**: **'' | ||
- | * Zeile **3**: **'' | ||
- | * Zeile **4**: **'' | ||
- | * Zeile **5**: **'' | ||
- | * Zeile **6**: **'' | ||
- | * Zeile **7**: **'' | ||
- | * Zeile **8**: **'' | ||
- | * Zeile **9**: **'' | ||
- | * Zeile **10**: | ||
- | * Zeile **11**: **'' | ||
- | * Zeile **12**: **'' | ||
- | * Zeile **13 - 16**: **'' | ||
- | * Zeile **17**: | ||
- | * Zeile **18**: **'' | ||
- | * Zeile **19 - 24**: **'' | ||
- | * Zeile **25**: | ||
- | * Zeile **26**: **'' | ||
- | * Zeile **27**: **'' | ||
- | |||
- | === Script ausführen === | ||
- | Nun wollen wir unser ersten Playbook ausführen, um auf dem Zielhost den gewünschten Benutzer anzulegen; hierzu rufen wir unser Script wie folgt auf: | ||
- | $ ansible-playbook -v 01_create-user.yml | ||
- | |||
- | < | ||
- | <font style=" | ||
- | <font style=" | ||
- | |||
- | PLAY [centos8] **************************************************************************************************************************************** | ||
- | |||
- | TASK [Gathering Facts] ****************************************************************************************************************************************</ | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | </ | ||
- | |||
- | === Script Ablaufbeschreibung === | ||
- | Bei jedem Ansible-Playbook werden beim Ausführen zu aller erst die sog. Facts durch Ansible gesammelt. | ||
- | |||
- | Anschließend werden die einzelnen Tasks (Aufgaben) der Reihe nach abgearbeitet. In der Zeile nach **TASK** wird dann die Beschreibung ausgegeben, die wir im YAML-Script nach dem Schlüsselwort **'' | ||
- | |||
- | Bei der Ausgabe werden Stati mit einer entsprechneden Farbe hinterlegt: | ||
- | * < | ||
- | * < | ||
- | * < | ||
- | |||
- | Eine Zusammenfasssung für jeden Host wir am ende unter dem Kennzeichen **PLAY RECAP** nochmals zusammengefasst. | ||
- | |||
- | === Protokollierung === | ||
- | Auf dem Zielhost werden die Aktivitäten des Ansible-Playbooks entsprechend protokolliert. | ||
- | # less / | ||
- | |||
- | < | ||
- | Jan 4 19:59:51 vml000090 sshd[11916]: | ||
- | Jan 4 19:59:51 vml000090 systemd[11920]: | ||
- | Jan 4 19:59:51 vml000090 sshd[11916]: | ||
- | Jan 4 19:59:58 vml000090 sudo[12053]: | ||
- | Jan 4 19:59:58 vml000090 sudo[12053]: | ||
- | Jan 4 19:59:58 vml000090 sudo[12053]: | ||
- | Jan 4 20:00:06 vml000090 sudo[12053]: | ||
- | Jan 4 20:00:12 vml000090 sudo[12213]: | ||
- | Jan 4 20:00:12 vml000090 sudo[12213]: | ||
- | Jan 4 20:00:12 vml000090 sudo[12213]: | ||
- | Jan 4 20:00:12 vml000090 groupadd[12222]: | ||
- | Jan 4 20:00:12 vml000090 groupadd[12222]: | ||
- | Jan 4 20:00:12 vml000090 groupadd[12222]: | ||
- | Jan 4 20:00:12 vml000090 sudo[12213]: | ||
- | Jan 4 20:00:14 vml000090 sudo[12330]: | ||
- | Jan 4 20:00:14 vml000090 sudo[12330]: | ||
- | Jan 4 20:00:14 vml000090 sudo[12330]: | ||
- | Jan 4 20:00:14 vml000090 useradd[12339]: | ||
- | Jan 4 20:00:14 vml000090 sudo[12330]: | ||
- | Jan 4 20:00:15 vml000090 sudo[12448]: | ||
- | Jan 4 20:00:15 vml000090 sudo[12448]: | ||
- | Jan 4 20:00:15 vml000090 sudo[12448]: | ||
- | Jan 4 20:00:16 vml000090 usermod[12455]: | ||
- | Jan 4 20:00:16 vml000090 sudo[12448]: | ||
- | |||
- | ==== 02: sudoers anpassen ==== | ||
- | Bei unserem zweiten Beispiel wollen wir lediglich dafür sorgen, dass die Nutzer der Gruppe **'' | ||
- | < | ||
- | %wheel ALL=(ALL) ALL</ | ||
- | |||
- | === Script anlegen === | ||
- | Hier legen wir nun unser erstes Script ab. | ||
- | $ vim 02_passwd_sudo_wheel.yml | ||
- | |||
- | <file bash 02_passwd_sudo_wheel.yml> | ||
- | - hosts: centos8 | ||
- | become: true | ||
- | vars: | ||
- | sudoers: ansible | ||
- | |||
- | tasks: | ||
- | - name: All users from groub ' | ||
- | copy: | ||
- | content: "# Allows people in group wheel to run all command\n%wheel | ||
- | dest: / | ||
- | owner: root | ||
- | group: root | ||
- | mode: " | ||
- | validate: visudo -cf %s</ | ||
- | |||
- | === Script Beschreibung === | ||
- | Die einzelnen Zeilen/ | ||
- | Zeile: | ||
- | * Zeile **1 - 5**: Der bereits bekannte Block aus dem **[[# | ||
- | * https:// | ||
- | * Zeile **6**: | ||
- | * Zeile **7**: **'' | ||
- | * Zeile **8**: **'' | ||
- | * Zeile **9 - 15**: **'' | ||
- | |||
- | === Script ausführen === | ||
- | Nun wollen wir unser ersten Playbook ausführen, um auf dem Zielhost eine Datei mit dem gewünschten Inhalt ablegen; hierzu rufen wir unser Script wie folgt auf: | ||
- | $ ansible-playbook -v 02_passwd_sudo_wheel.yml | ||
- | |||
- | < | ||
- | <font style=" | ||
- | <font style=" | ||
- | |||
- | PLAY [centos8] **************************************************************************************************************************************** | ||
- | |||
- | TASK [Gathering Facts] ****************************************************************************************************************************************</ | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | </ | ||
- | |||
- | === Ergebnis === | ||
- | Auf dem Zielhost findet sich nun unsere gewünschte Datei mit dem zugehörigen Inhalt. | ||
- | # cat / | ||
- | |||
- | <file bash / | ||
- | %wheel | ||
- | |||
- | |||
- | ==== 03: mehrere Benutzer anlegen und SSH-Schlüssel kopieren ==== | ||
- | Beim drittem Playbook-Beispiel wollen wir mit Hilfe von Ansible nicht nur ein Admin-Konto sondern gleich mehrere anlegen. Dabei kopieren wir dann auch noch gleich die zugehörigen öffentlichen SSH-Schlüssel an Ort und Stelle. Zu guter Letzt stellen wir noch sicher dass der Eintrag **'' | ||
- | |||
- | Bevor wir unser erstes Script schreiben, wechseln wir in unser zuvor angelegtes Zielverzeichnis: | ||
- | $ cd ~/ansible | ||
- | |||
- | === Script anlegen === | ||
- | Nun legen wir nun unser erstes Script ab. | ||
- | $ vim 03_create-admins.yml | ||
- | |||
- | <file bash 03_create-admins.yml> | ||
- | - hosts: centos8 | ||
- | become: true | ||
- | vars: | ||
- | sudoers: ansible | ||
- | |||
- | tasks: | ||
- | - name: add several users to the system | ||
- | user: | ||
- | name: "{{ item.name }}" | ||
- | comment: "{{ item.fullname }}" | ||
- | uid: "{{ item.uid }}" | ||
- | groups: "{{ item.groups }}" | ||
- | state: present | ||
- | with_items: | ||
- | - { name: bofh, fullname: " | ||
- | - { name: ruben, fullname: "Ruben Nausch", | ||
- | - { name: ansible, fullname: " | ||
- | |||
- | - name: Initial password generation for each user | ||
- | shell: usermod -p $(echo '{{ item.secret }}' | openssl passwd -1 -stdin) {{ item.name }} | ||
- | with_items: | ||
- | - { name: bofh, secret: "/ | ||
- | - { name: ruben, secret: " | ||
- | - { name: ansible, secret: " | ||
- | |||
- | - name: Set authorized keys for each user | ||
- | authorized_key: | ||
- | user: "{{ item.name }}" | ||
- | state: present | ||
- | key: "{{ lookup(' | ||
- | with_items: | ||
- | - {name: bofh } | ||
- | - {name: ruben } | ||
- | - {name: ansible } | ||
- | |||
- | - include_tasks: | ||
- | </ | ||
- | |||
- | === Script Beschreibung === | ||
- | Das Script ist soweit selbsterklärend, | ||
- | * **Task 1** : Drei Userkonten anlegen - die betreffenden Daten für unsere User holen wir uns dabei aus einer Liste (array) | ||
- | * **Task 2** : Setzen der initialen Passwörter je Userkonto | ||
- | * **Task 3** : Kopieren der jeweiligen öffentlichen SSH-Schlüssel der User. In diesem Konfigurationsbeispiel liegen diese im Verzeichnis **''/ | ||
- | -rw-r--r--. 1 django django 100 4. Jan 22:12 ansible.pub | ||
- | -rw-r--r--. 1 django django 108 4. Jan 22:13 bofh.pub | ||
- | -rw-r--r--. 1 django django | ||
- | * **Task 4** : Das Anpassen der **sudoers**-Eigenschaften haben wir in diesem Konfigurationsbeispiel in eine separate YAML-Datei ausgelagert. Hierzu nutzen wir das YAML-Modul **[[https:// | ||
- | - name: All users from groub ' | ||
- | copy: | ||
- | content: "# Allows people in group wheel to run all command\n%wheel | ||
- | dest: / | ||
- | owner: root | ||
- | group: root | ||
- | mode: " | ||
- | validate: visudo -cf %s | ||
- | </ | ||
- | |||
- | |||
- | === Script ausführen === | ||
- | Nun wollen wir unser Playbook ausführen, um auf dem Zielhost den gewünschten Benutzer anzulegen; hierzu rufen wir unser Script wie folgt auf: | ||
- | $ ansible-playbook -v 03_create-admins.yml03_create-admins.yml | ||
- | |||
- | < | ||
- | <font style=" | ||
- | <font style=" | ||
- | |||
- | PLAY [centos8] **************************************************************************************************************************************** | ||
- | |||
- | TASK [Gathering Facts] ****************************************************************************************************************************************</ | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | changed: [www8.dmz.nausch.org] => (item={' | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | changed: [www8.dmz.nausch.org] => (item={' | ||
- | changed: [www8.dmz.nausch.org] => (item={' | ||
- | <font style=" | ||
- | <font style=" | ||
- | changed: [www8.dmz.nausch.org] => (item={' | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | </ | ||
- | |||
- | === Ergebnis === | ||
- | Auf dem Zielhost findet sich nun unsere gewünschte Datei mit dem zugehörigen Inhalt. | ||
- | # cat / | ||
- | |||
- | <file bash / | ||
- | %wheel | ||
- | |||
- | Auch unsere drei Nutzer-/ | ||
- | < | ||
- | ├── ansible | ||
- | │ ├── .bash_logout | ||
- | │ ├── .bash_profile | ||
- | │ ├── .bashrc | ||
- | │ ├── .ssh | ||
- | │ │ └── authorized_keys | ||
- | ├── bofh | ||
- | │ ├── .bash_logout | ||
- | │ ├── .bash_profile | ||
- | │ ├── .bashrc | ||
- | │ └── .ssh | ||
- | │ | ||
- | └── ruben | ||
- | ├── .bash_logout | ||
- | ├── .bash_profile | ||
- | ├── .bashrc | ||
- | └── .ssh | ||
- | └── authorized_keys</ | ||
- | |||
- | ==== 04: Bedingtes Kopieren ==== | ||
- | Im vierten Beispiel wollen wir die Konfigurationsdatei **'' | ||
- | |||
- | === Script anlegen === | ||
- | Das Script legen wir wie auch schon bei den anderen Beispielen zuvor im Verzeichnis **'' | ||
- | $ vim 04_repro.yml | ||
- | |||
- | <file bash 04_repro.yml> | ||
- | - hosts: all | ||
- | become: true | ||
- | vars: | ||
- | sudoers: ansible | ||
- | |||
- | tasks: | ||
- | - name: Place repo-file mailserver.guru for CentOS 8 right in place | ||
- | copy: | ||
- | src: / | ||
- | dest: / | ||
- | when: | ||
- | - ansible_facts[' | ||
- | - ansible_facts[' | ||
- | |||
- | - name: Place repo-file mailserver.guru for CentOS 7 right in place | ||
- | copy: | ||
- | src: files/ | ||
- | dest: / | ||
- | when: | ||
- | - ansible_facts[' | ||
- | - ansible_facts[' | ||
- | |||
- | </ | ||
- | |||
- | Im Arbeitsverzeichnis für unsere Ansible hatten wir **[[# | ||
- | $ mkdir ~/ | ||
- | $ mkdir ~/ | ||
- | |||
- | \\ | ||
- | Die **CentOS 7** spezifische Repo-Datei **'' | ||
- | $ vim ~/ | ||
- | |||
- | <file bash ~/ | ||
- | [mailserver.guru-os] | ||
- | name=Extra (Mailserver-)Packages for Enterprise Linux 7 - $basearch | ||
- | baseurl=http:// | ||
- | priority=5 | ||
- | enabled=1 | ||
- | gpgcheck=1 | ||
- | gpgkey=file:/// | ||
- | |||
- | |||
- | [mailserver.guru-testing] | ||
- | name=Testing (Mailserver-)Packages for Enterprise Linux 7 - $basearch | ||
- | baseurl=http:// | ||
- | #priority=5 | ||
- | enabled=0 | ||
- | gpgcheck=1 | ||
- | gpgkey=file:/// | ||
- | |||
- | Die **CentOS 8** spezifische Repo-Datei **'' | ||
- | $ vim ~/ | ||
- | |||
- | <file bash ~/ | ||
- | [mailserver.guru-os] | ||
- | name=Extra (Mailserver-)Packages for Enterprise Linux 8 - $basearch | ||
- | baseurl=http:// | ||
- | priority=5 | ||
- | enabled=1 | ||
- | gpgcheck=1 | ||
- | gpgkey=file:/// | ||
- | |||
- | |||
- | [mailserver.guru-testing] | ||
- | name=Testing (Mailserver-)Packages for Enterprise Linux 8 - $basearch | ||
- | baseurl=http:// | ||
- | #priority=5 | ||
- | enabled=0 | ||
- | gpgcheck=1 | ||
- | gpgkey=file:/// | ||
- | |||
- | === Script Beschreibung === | ||
- | Unser Playbook, welches alle Hosts anspricht besteht im Wesentlichen aus zwei Tasks/ | ||
- | |||
- | Zum Kopieren wird dann das Ansible Modul **[[https:// | ||
- | $ ansible-doc copy | ||
- | |||
- | < | ||
- | |||
- | The `copy' module copies a file from the local or remote machine to a location on the remote | ||
- | machine. Use the [fetch] module to copy files from remote locations to the local box. If you need | ||
- | variable interpolation in copied files, use the [template] module. For Windows targets, use the | ||
- | [win_copy] module instead. | ||
- | |||
- | * note: This module has a corresponding action plugin. | ||
- | |||
- | OPTIONS (= is mandatory): | ||
- | |||
- | - attributes | ||
- | Attributes the file or directory should have. To get supported flags look at the man page for | ||
- | `chattr' | ||
- | one displayed by `lsattr' | ||
- | (Aliases: attr)[Default: | ||
- | version_added: | ||
- | |||
- | - backup | ||
- | Create a backup file including the timestamp information so you can get the original file back if | ||
- | you somehow clobbered it incorrectly. | ||
- | [Default: no] | ||
- | type: bool | ||
- | version_added: | ||
- | |||
- | - content | ||
- | When used instead of `src', sets the contents of a file directly to the specified value. For | ||
- | anything advanced or with formatting also look at the template module. | ||
- | [Default: (null)] | ||
- | version_added: | ||
- | |||
- | - decrypt | ||
- | This option controls the autodecryption of source files using vault. | ||
- | [Default: Yes] | ||
- | type: bool | ||
- | version_added: | ||
- | |||
- | = dest | ||
- | Remote absolute path where the file should be copied to. If `src' is a directory, this must be a | ||
- | directory too. If `dest' is a nonexistent path and if either `dest' ends with "/" | ||
- | directory, `dest' is created. If `src' and `dest' are files, the parent directory of `dest' isn't | ||
- | created: the task fails if it doesn' | ||
- | |||
- | |||
- | - directory_mode | ||
- | When doing a recursive copy set the mode for the directories. If this is not set we will use the | ||
- | system defaults. The mode is only set on directories which are newly created, and will not affect | ||
- | those that already existed. | ||
- | [Default: (null)] | ||
- | version_added: | ||
- | |||
- | - follow | ||
- | This flag indicates that filesystem links in the destination, | ||
- | [Default: no] | ||
- | type: bool | ||
- | version_added: | ||
- | |||
- | - force | ||
- | the default is `yes', which will replace the remote file when contents are different than the | ||
- | source. If `no', the file will only be transferred if the destination does not exist. | ||
- | (Aliases: thirsty)[Default: | ||
- | type: bool | ||
- | version_added: | ||
- | |||
- | - group | ||
- | Name of the group that should own the file/ | ||
- | [Default: None] | ||
- | |||
- | - local_follow | ||
- | This flag indicates that filesystem links in the source tree, if they exist, should be followed. | ||
- | [Default: yes] | ||
- | type: bool | ||
- | version_added: | ||
- | |||
- | - mode | ||
- | Mode the file or directory should be. For those used to `/ | ||
- | actually octal numbers (like 0644). Leaving off the leading zero will likely have unexpected | ||
- | results. As of version 1.8, the mode may be specified as a symbolic mode (for example, `u+rwx' | ||
- | `u=rw, | ||
- | [Default: None] | ||
- | |||
- | - owner | ||
- | Name of the user that should own the file/ | ||
- | [Default: None] | ||
- | |||
- | - remote_src | ||
- | If `no', it will search for `src' at originating/ | ||
- | If `yes' it will go to the remote/ | ||
- | Currently `remote_src' | ||
- | [Default: no] | ||
- | type: bool | ||
- | version_added: | ||
- | |||
- | - selevel | ||
- | Level part of the SELinux file context. This is the MLS/MCS attribute, sometimes known as the | ||
- | `range' | ||
- | [Default: s0] | ||
- | |||
- | - serole | ||
- | Role part of SELinux file context, `_default' | ||
- | [Default: None] | ||
- | |||
- | - setype | ||
- | Type part of SELinux file context, `_default' | ||
- | [Default: None] | ||
- | |||
- | - seuser | ||
- | User part of SELinux file context. Will default to system policy, if applicable. If set to | ||
- | `_default', | ||
- | [Default: None] | ||
- | |||
- | - src | ||
- | Local path to a file to copy to the remote server; can be absolute or relative. If path is a | ||
- | directory, it is copied recursively. In this case, if path ends with "/", | ||
- | that directory are copied to destination. Otherwise, if it does not end with "/", | ||
- | itself with all contents is copied. This behavior is similar to Rsync. | ||
- | [Default: (null)] | ||
- | |||
- | - unsafe_writes | ||
- | Normally this module uses atomic operations to prevent data corruption or inconsistent reads from | ||
- | the target files, sometimes systems are configured or just broken in ways that prevent this. One | ||
- | example are docker mounted files, they cannot be updated atomically and can only be done in an | ||
- | unsafe manner. | ||
- | This boolean option allows ansible to fall back to unsafe methods of updating files for those | ||
- | cases in which you do not have any other choice. Be aware that this is subject to race conditions | ||
- | and can lead to data corruption. | ||
- | [Default: False] | ||
- | type: bool | ||
- | version_added: | ||
- | |||
- | - validate | ||
- | The validation command to run before copying into place. The path to the file to validate is | ||
- | passed in via ' | ||
- | so shell features like expansion and pipes won't work. | ||
- | [Default: None] | ||
- | |||
- | |||
- | NOTES: | ||
- | * The [copy] module recursively copy facility does not scale to lots (> | ||
- | For alternative, | ||
- | * For Windows targets, use the [win_copy] module instead. | ||
- | |||
- | AUTHOR: Ansible Core Team, Michael DeHaan | ||
- | EXTENDS_DOCUMENTATION_FRAGMENT: | ||
- | METADATA: | ||
- | status: | ||
- | - stableinterface | ||
- | supported_by: | ||
- | | ||
- | |||
- | EXAMPLES: | ||
- | # Example from Ansible Playbooks | ||
- | - copy: | ||
- | src: / | ||
- | dest: / | ||
- | owner: foo | ||
- | group: foo | ||
- | mode: 0644 | ||
- | |||
- | # The same example as above, but using a symbolic mode equivalent to 0644 | ||
- | - copy: | ||
- | src: / | ||
- | dest: / | ||
- | owner: foo | ||
- | group: foo | ||
- | mode: u=rw, | ||
- | |||
- | # Another symbolic mode example, adding some permissions and removing others | ||
- | - copy: | ||
- | src: / | ||
- | dest: / | ||
- | owner: foo | ||
- | group: foo | ||
- | mode: u+rw, | ||
- | |||
- | # Copy a new " | ||
- | - copy: | ||
- | src: / | ||
- | dest: / | ||
- | owner: root | ||
- | group: root | ||
- | mode: 0644 | ||
- | backup: yes | ||
- | |||
- | # Copy a new " | ||
- | - copy: | ||
- | src: / | ||
- | dest: / | ||
- | validate: / | ||
- | |||
- | # Copy a " | ||
- | - copy: | ||
- | src: / | ||
- | dest: / | ||
- | remote_src: yes | ||
- | validate: / | ||
- | |||
- | # Create a CSV file from your complete inventory using an inline template | ||
- | - hosts: all | ||
- | tasks: | ||
- | - copy: | ||
- | content: | | ||
- | HOSTNAME; | ||
- | {% for host in hostvars %} | ||
- | {% set vars = hostvars[host|string] %} | ||
- | {{ vars.ansible_hostname }};{{ vars.remote_host }};{{ vars.ansible_fqdn }};{{ vars.ansible_distribution }};{{ vars.ansible_d | ||
- | {% endfor %} | ||
- | dest: / | ||
- | backup: yes | ||
- | run_once: yes | ||
- | delegate_to: | ||
- | |||
- | RETURN VALUES: | ||
- | |||
- | |||
- | dest: | ||
- | description: | ||
- | returned: success | ||
- | type: string | ||
- | sample: / | ||
- | src: | ||
- | description: | ||
- | returned: changed | ||
- | type: string | ||
- | sample: / | ||
- | md5sum: | ||
- | description: | ||
- | returned: when supported | ||
- | type: string | ||
- | sample: 2a5aeecc61dc98c4d780b14b330e3282 | ||
- | checksum: | ||
- | description: | ||
- | returned: success | ||
- | type: string | ||
- | sample: 6e642bb8dd5c2e027bf21dd923337cbb4214f827 | ||
- | backup_file: | ||
- | description: | ||
- | returned: changed and if backup=yes | ||
- | type: string | ||
- | sample: / | ||
- | gid: | ||
- | description: | ||
- | returned: success | ||
- | type: int | ||
- | sample: 100 | ||
- | group: | ||
- | description: | ||
- | returned: success | ||
- | type: string | ||
- | sample: httpd | ||
- | owner: | ||
- | description: | ||
- | returned: success | ||
- | type: string | ||
- | sample: httpd | ||
- | uid: | ||
- | description: | ||
- | returned: success | ||
- | type: int | ||
- | sample: 100 | ||
- | mode: | ||
- | description: | ||
- | returned: success | ||
- | type: string | ||
- | sample: 0644 | ||
- | size: | ||
- | description: | ||
- | returned: success | ||
- | type: int | ||
- | sample: 1220 | ||
- | state: | ||
- | description: | ||
- | returned: success | ||
- | type: string | ||
- | sample: file | ||
- | |||
- | </ | ||
- | Wollen wir direkt ein **snippet** für unser Playbook zum Kopieren haben, geben wir bei dem Befehl **'' | ||
- | $ ansible-doc copy -s | ||
- | < | ||
- | copy: | ||
- | attributes: | ||
- | | ||
- | | ||
- | backup: | ||
- | you somehow clobbered it incorrectly. | ||
- | content: | ||
- | | ||
- | | ||
- | decrypt: | ||
- | dest: # (required) Remote absolute path where the file should be copied to. If `src' is a directory, this | ||
- | must be a directory too. If `dest' is a nonexistent path and if | ||
- | | ||
- | | ||
- | | ||
- | directory_mode: | ||
- | | ||
- | | ||
- | follow: | ||
- | force: | ||
- | | ||
- | does not exist. | ||
- | group: | ||
- | local_follow: | ||
- | mode: # Mode the file or directory should be. For those used to `/ | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | owner: | ||
- | remote_src: | ||
- | | ||
- | | ||
- | selevel: | ||
- | | ||
- | serole: | ||
- | setype: | ||
- | seuser: | ||
- | | ||
- | | ||
- | src: # Local path to a file to copy to the remote server; can be absolute or relative. If path is a | ||
- | | ||
- | "/", | ||
- | | ||
- | | ||
- | | ||
- | unsafe_writes: | ||
- | the target files, sometimes systems are configured or just broken in | ||
- | ways that prevent this. One example are docker mounted files, they | ||
- | | ||
- | | ||
- | | ||
- | any other choice. Be aware that this is subject to race conditions | ||
- | and can lead to data corruption. | ||
- | validate: | ||
- | in via ' | ||
- | | ||
- | | ||
- | </ | ||
- | |||
- | === Script ausführen === | ||
- | Zum Kopieren der unterschiedlichen Dateien rufen wir nun unser Playbook wie folgt auf: | ||
- | $ ansible-playbook -v 04_repro.yml | ||
- | |||
- | < | ||
- | <font style=" | ||
- | <font style=" | ||
- | |||
- | PLAY [all] ***************************************************************************************************************************** | ||
- | |||
- | TASK [Gathering Facts] *****************************************************************************************************************</ | ||
- | <font style=" | ||
- | ok: [www8.dmz.nausch.org]</ | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | </ | ||
- | |||
- | \\ | ||
- | Die < | ||
- | Die Ursache hierzu ist einfach erklärt: Da wir die Prüfung auf die CentOS-Version **7** und **8** auf beiden Hosts ausführen, führt natürlich immer nur zu einem Treffer, der jeweils " | ||
- | |||
- | === Ergebnis === | ||
- | Auf dem Zielhost findet sich nun unsere gewünschte Datei mit dem zugehörigen Inhalt an Ort und Stelle. | ||
- | # ll / | ||
- | |||
- | < | ||
- | |||
- | ==== 05: NTP-Daemon chrony installieren und konfigurieren ==== | ||
- | In folgendem Beispiel Nummer fünf wollen wir auf unseren **CentOS 8**-Hosts den NTP-Deamon **[[https:// | ||
- | |||
- | === Script anlegen === | ||
- | Das Script legen wir wie auch schon bei den anderen Beispielen zuvor im Verzeichnis **'' | ||
- | $ vim 05_chrony.yml | ||
- | |||
- | <file bash 05_chrony.yml> | ||
- | - hosts: centos8 | ||
- | become: true | ||
- | vars: | ||
- | sudoers: ansible | ||
- | config_file: | ||
- | # chronyd client config-options | ||
- | chrony_pool: | ||
- | chrony_stratumweight: | ||
- | chrony_makestep: | ||
- | |||
- | tasks: | ||
- | - name: Install chrony ntp Deamon | ||
- | dnf: | ||
- | # | ||
- | name: chrony | ||
- | state: latest | ||
- | |||
- | - name: Check if / | ||
- | stat: | ||
- | # | ||
- | path: / | ||
- | register: stat_result | ||
- | |||
- | - name: Make a copy of / | ||
- | copy: | ||
- | # | ||
- | remote_src: yes | ||
- | src: / | ||
- | dest: / | ||
- | when: stat_result.stat.exists == False | ||
- | |||
- | - name: Copy template config-file in place | ||
- | template: | ||
- | # | ||
- | src: templates/ | ||
- | dest: "{{ config_file }}" | ||
- | |||
- | - name: Make sure Chrony is started up | ||
- | service: | ||
- | # | ||
- | name: chronyd | ||
- | state: started | ||
- | enabled: yes | ||
- | |||
- | </ | ||
- | |||
- | Die Konfigurationsdatei unseres chrony-Daemon werden wir im Arbeitsbereich unserer ansible-Umgebung auf dem Admin-Rechner/ | ||
- | $ mkdir -p ~/ | ||
- | |||
- | Ansible nutzt die **[[https:// | ||
- | |||
- | |||
- | $ vim ~/ | ||
- | |||
- | <file bash ~/ | ||
- | # Please consider joining the pool (http:// | ||
- | {{ chrony_pool }} | ||
- | |||
- | # Ignore stratum in source selection | ||
- | {{ chrony_stratumweight }} | ||
- | |||
- | # Record the rate at which the system clock gains/ | ||
- | driftfile / | ||
- | |||
- | # Allow the system clock to be stepped in the first three updates | ||
- | # if its offset is larger than 1 second. | ||
- | makestep 1.0 3 | ||
- | |||
- | # Enable kernel synchronization of the real-time clock (RTC). | ||
- | rtcsync | ||
- | |||
- | # In first three updates step the system clock instead of slew | ||
- | # if the adjustment is larger than 10 seconds. | ||
- | {{ chrony_makestep }} | ||
- | |||
- | # Enable hardware timestamping on all interfaces that support it. | ||
- | # | ||
- | |||
- | # Increase the minimum number of selectable sources required to adjust | ||
- | # the system clock. | ||
- | #minsources 2 | ||
- | |||
- | # Allow NTP client access from local network. | ||
- | #allow 192.168.0.0/ | ||
- | |||
- | # Serve time even if not synchronized to a time source. | ||
- | #local stratum 10 | ||
- | |||
- | # Specify file containing keys for NTP authentication. | ||
- | keyfile / | ||
- | |||
- | # Get TAI-UTC offset and leap seconds from the system tz database. | ||
- | leapsectz right/UTC | ||
- | |||
- | # Specify directory for log files. | ||
- | logdir / | ||
- | |||
- | # Select which information is logged. | ||
- | #log measurements statistics tracking | ||
- | |||
- | </ | ||
- | |||
- | Die drei Konfigurationsoptionen, | ||
- | * **'' | ||
- | * **'' | ||
- | * **'' | ||
- | |||
- | === Script Beschreibung === | ||
- | Im Playbook greifen wir auf folgende Ansible-Module zurück: | ||
- | * **[[https:// | ||
- | * **[[https:// | ||
- | * **[[https:// | ||
- | * **[[https:// | ||
- | |||
- | In unserem Playbook werden am Anfang den entsprechenden Variablen ihre werte zugewiesen. Im Anschluss daran werden fünft **'' | ||
- | - Aufgabe: Installation des chrony NTP-Daemon | ||
- | - Aufgabe: Überprüfen ob von der Konfigurationsdatei, | ||
- | - Aufgabe: Sofern bei der Prüfung in Aufgabe **2** noch keine Sicherungskopie erstellt wurde, wird eine Sicherungsopie erstellt. | ||
- | - Aufgabe: Konfigurieren unseres chrony-Daemon | ||
- | - Aufgabe: Starten des chrony-Daemon und aktivieren des automatischen Starts beim Starten des Hosts | ||
- | |||
- | === Script ausführen === | ||
- | Zum Kopieren der unterschiedlichen Dateien rufen wir nun unser Playbook wie folgt auf: | ||
- | $ ansible-playbook -v 05_chrony.yml | ||
- | |||
- | < | ||
- | <font style=" | ||
- | <font style=" | ||
- | |||
- | PLAY [centos8] ************************************************************************************************************************* | ||
- | |||
- | TASK [Gathering Facts] *****************************************************************************************************************</ | ||
- | <font style=" | ||
- | ok: [www8.dmz.nausch.org]</ | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" | ||
- | <font style=" |