commit bf517e622bcc095e19eb59a4189ee4c404c78390 Author: Michael Wilson Date: Tue Jan 11 16:02:21 2022 +0100 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e4e275c --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*/files/*_private +*.swp +*_private +id_rsa diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/add_to_icinga2/defaults/main.yml b/add_to_icinga2/defaults/main.yml new file mode 100644 index 0000000..f8213d6 --- /dev/null +++ b/add_to_icinga2/defaults/main.yml @@ -0,0 +1,12 @@ +tcp_port_monitoring: + autodetect_ports: true + no_autodetect_port_list: + - "22" + - "ports have to be strings" +icinga2_monitoring_master: + host: monitoring.example.com + api_port: 5665 + api_user: root + api_password: SomePassword + ssh_user: _icinga2 + ssh_pubkey: 'ssh-rsa XXXX' diff --git a/add_to_icinga2/files/check_services_openbsd.sh b/add_to_icinga2/files/check_services_openbsd.sh new file mode 100644 index 0000000..9bd0a86 --- /dev/null +++ b/add_to_icinga2/files/check_services_openbsd.sh @@ -0,0 +1,19 @@ +#!/bin/ksh + +failed_services=$(doas /usr/sbin/rcctl ls failed) +failed_rc=$? +failed_services_count=$(echo "$failed_services" | wc -w | xargs) +check_rc=3 +check_output="UNKNOWN - something wrent wrong: $failed_services" +perfdata="'failed_services'=$failed_services_count" + +if [[ $failed_rc -eq 0 && $failed_services_count -eq 0 ]]; then + check_output="OK - all services are running" + check_rc=0 +elif [[ $failed_rc -eq 1 && $failed_services_count -gt 0 ]]; then + check_output="CRITICAL - $failed_services_count service(s) not running: $failed_services" + check_rc=2 +fi + +echo "$check_output | $perfdata" +exit $check_rc diff --git a/add_to_icinga2/files/listening_tcp_openbsd.sh b/add_to_icinga2/files/listening_tcp_openbsd.sh new file mode 100644 index 0000000..c5062c0 --- /dev/null +++ b/add_to_icinga2/files/listening_tcp_openbsd.sh @@ -0,0 +1,17 @@ +#!/bin/ksh +ports=$(netstat -lnptcp -finet | awk '{ print $4 }' |grep '\.' | sed 's/*./0.0.0.0./g' | grep -v '127\.0\.0\.1' | cut -f 5 -d '.' | sort | uniq) +ports_len=$(echo $ports | awk '{ print NF - 1 }') + +echo "[ " + +i=0 +for port in $ports; do + if [[ $i -lt $ports_len ]]; then + echo " \"$port\"," + else + echo " \"$port\"" + fi + ((i=i+1)) +done + +echo " ]" diff --git a/add_to_icinga2/tasks/common.yml b/add_to_icinga2/tasks/common.yml new file mode 100644 index 0000000..820dd0f --- /dev/null +++ b/add_to_icinga2/tasks/common.yml @@ -0,0 +1,13 @@ +- name: create ssh user + become: yes + user: + name: "{{ icinga2_monitoring_master.ssh_user }}" + state: present + +- name: set authorized_keys + become: yes + authorized_key: + user: "{{ icinga2_monitoring_master.ssh_user }}" + state: present + key: "{{ icinga2_monitoring_master.ssh_pubkey }}" + diff --git a/add_to_icinga2/tasks/main.yml b/add_to_icinga2/tasks/main.yml new file mode 100644 index 0000000..2f78cac --- /dev/null +++ b/add_to_icinga2/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- name: common setup + include: "common.yml" +- name: ubuntu setup + include: "ubuntu.yml" + when: ansible_distribution == 'Ubuntu' +- name: openbsd setup + include: "openbsd.yml" + when: ansible_distribution | lower == 'openbsd' diff --git a/add_to_icinga2/tasks/openbsd.yml b/add_to_icinga2/tasks/openbsd.yml new file mode 100644 index 0000000..c66c54e --- /dev/null +++ b/add_to_icinga2/tasks/openbsd.yml @@ -0,0 +1,97 @@ +- name: ensure facts dir exists + become: yes + file: + path: "{{ item }}" + state: directory + loop: + - /etc/ansible + - /etc/ansible/facts.d + +- name: deploy custom fact for listening tcp ports + become: yes + copy: + src: listening_tcp_openbsd.sh + dest: /etc/ansible/facts.d/listening_tcp.fact + mode: '0755' + register: fact_deploy + +- name: reload facts + setup: + when: fact_deploy.changed + +- name: print to be monitored tcp ports + debug: + msg: "{{ monitored_tcp_ports }}" + +- name: copy service check + become: yes + copy: + src: check_services_openbsd.sh + dest: /usr/local/libexec/nagios/check_services.sh + mode: '0755' + +- name: allow list of failed services via doas + become: yes + lineinfile: + path: /etc/doas.conf + create: yes + regexp: '^permit.*{{ icinga2_monitoring_master.ssh_user }}.*$' + line: 'permit nopass {{ icinga2_monitoring_master.ssh_user }} as root cmd /usr/sbin/rcctl args ls failed' + +- name: set fact with monitoring config + set_fact: + api_body: '{ "templates": [ "openbsd" ], "attrs": { "address": "{{ ansible_fqdn }}", "vars.tcp_ipv4": {{ monitored_tcp_ports }} }, "pretty": true }' + +- name: write monitoring config + become: yes + copy: + dest: /etc/monitoring.conf + content: "{{ api_body }}" + register: monitoring_config + +- name: delete host from icinga + uri: + url: "{{ icinga2_api_url }}/v1/objects/hosts/{{ ansible_fqdn }}?cascade=1" + method: DELETE + return_content: yes + headers: + Accept: application/json + body_format: json + validate_certs: no + url_username: "{{ icinga2_monitoring_master.api_user }}" + url_password: "{{ icinga2_monitoring_master.api_password }}" + when: monitoring_config.changed + failed_when: false + changed_when: true + throttle: 1 + +- name: add host to icinga + uri: + url: "{{ icinga2_api_url }}/v1/objects/hosts/{{ ansible_fqdn }}" + method: PUT + return_content: yes + headers: + Accept: application/json + body_format: json + body: "{{ api_body }}" + validate_certs: no + url_username: "{{ icinga2_monitoring_master.api_user }}" + url_password: "{{ icinga2_monitoring_master.api_password }}" + when: monitoring_config.changed + changed_when: true + throttle: 1 + +- name: trigger icinga restart + uri: + url: "{{ icinga2_api_url }}/v1/actions/restart-process?pretty=1" + method: POST + return_content: yes + headers: + Accept: application/json + body_format: json + validate_certs: no + url_username: "{{ icinga2_monitoring_master.api_user }}" + url_password: "{{ icinga2_monitoring_master.api_password }}" + when: monitoring_config.changed + changed_when: true + throttle: 1 diff --git a/add_to_icinga2/tasks/ubuntu.yml b/add_to_icinga2/tasks/ubuntu.yml new file mode 100644 index 0000000..502e111 --- /dev/null +++ b/add_to_icinga2/tasks/ubuntu.yml @@ -0,0 +1,26 @@ +- name: add host to icinga + uri: + url: "{{ icinga2_api_url }}/v1/objects/hosts/{{ ansible_fqdn }}" + method: PUT + return_content: yes + headers: + Accept: application/json + body_format: json + body: '{ "templates": [ "linux" ], "attrs": { "address": "{{ ansible_fqdn }}" }, "pretty": true }' + validate_certs: no + url_username: "{{ icinga2_monitoring_master.api_user }}" + url_password: "{{ icinga2_monitoring_master.api_password }}" + failed_when: false + +- name: update host information in icinga + uri: + url: "{{ icinga2_api_url }}/v1/objects/hosts/{{ ansible_fqdn }}" + method: POST + return_content: yes + headers: + Accept: application/json + body_format: json + body: '{ "templates": [ "linux" ], "attrs": { "address": "{{ ansible_fqdn }}" }, "pretty": true }' + validate_certs: no + url_username: "{{ icinga2_monitoring_master.api_user }}" + url_password: "{{ icinga2_monitoring_master.api_password }}" diff --git a/add_to_icinga2/vars/main.yml b/add_to_icinga2/vars/main.yml new file mode 100644 index 0000000..333bd4f --- /dev/null +++ b/add_to_icinga2/vars/main.yml @@ -0,0 +1,2 @@ +icinga2_api_url: "https://{{ icinga2_monitoring_master.host }}:{{ icinga2_monitoring_master.api_port }}" +monitored_tcp_ports: "{% if tcp_port_monitoring.autodetect_ports %} {{ ansible_local.listening_tcp }} {% else %} {{ tcp_port_monitoring.no_autodetect_port_list }} {% endif %}" diff --git a/ansible_runner/defaults/main.yml b/ansible_runner/defaults/main.yml new file mode 100644 index 0000000..1a872ef --- /dev/null +++ b/ansible_runner/defaults/main.yml @@ -0,0 +1,10 @@ +ansible_runner_mailto: root@localhost +ansible_runner_command: "ansible-playbook playbook.yml -e do_backup=true" +ansible_runner_user: _runner +ansible_runner_home: /home/_runner +ansible_runner_schedule: + - name: my-deployment + repo: git@gitserver:user/my-deployment + minute: "~" + hour: "1~5" + weekday: "*" diff --git a/ansible_runner/handlers/main.yml b/ansible_runner/handlers/main.yml new file mode 100644 index 0000000..e945211 --- /dev/null +++ b/ansible_runner/handlers/main.yml @@ -0,0 +1,3 @@ +- name: update_aliases + become: yes + command: smtpctl update table aliases diff --git a/ansible_runner/tasks/main.yml b/ansible_runner/tasks/main.yml new file mode 100644 index 0000000..68d65fe --- /dev/null +++ b/ansible_runner/tasks/main.yml @@ -0,0 +1,72 @@ +- name: create user + become: yes + user: + name: "{{ ansible_runner_user }}" + shell: "/sbin/nologin" + home: "{{ ansible_runner_home }}" + +- name: install packages + become: yes + community.general.openbsd_pkg: + name: [ "git", "ansible" ] + state: present + snapshot: "{{ force_openbsd_snapshot | default(false) }}" + +- name: create ssh key + become: yes + openssh_keypair: + path: "{{ ansible_runner_home }}/.ssh/id_rsa" + owner: "{{ ansible_runner_user }}" + +- name: clone deployments + become: yes + git: + key_file: "{{ ansible_runner_home }}/.ssh/id_rsa" + accept_hostkey: yes + repo: "{{ deployment.repo }}" + dest: "{{ ansible_runner_home }}/{{ deployment.name }}" + loop: "{{ ansible_runner_schedule }}" + loop_control: + loop_var: deployment + +- name: set permissions + become: yes + file: + path: "{{ ansible_runner_home }}/{{ deployment.name }}" + owner: "{{ ansible_runner_user }}" + recurse: yes + loop: "{{ ansible_runner_schedule }}" + loop_control: + loop_var: deployment + +- name: setup run scripts + become: yes + template: + src: run_deployment.sh + dest: "{{ ansible_runner_home }}/{{ deployment.name }}/run_deployment.sh" + mode: '0750' + owner: "{{ ansible_runner_user }}" + loop: "{{ ansible_runner_schedule }}" + loop_control: + loop_var: deployment + +- name: setup cron jobs + become: yes + cron: + user: "{{ ansible_runner_user }}" + name: "{{ deployment.name }}" + job: "{{ ansible_runner_home }}/{{ deployment.name }}/run_deployment.sh" + minute: "{{ deployment.minute }}" + hour: "{{ deployment.hour }}" + weekday: "{{ deployment.weekday }}" + loop: "{{ ansible_runner_schedule }}" + loop_control: + loop_var: deployment + +- name: setup mail alias + become: yes + lineinfile: + path: /etc/mail/aliases + line: "{{ ansible_runner_user }}: {{ ansible_runner_mailto }}" + regexp: "^.*{{ ansible_runner_user }}.*$" + notify: update_aliases diff --git a/ansible_runner/templates/run_deployment.sh b/ansible_runner/templates/run_deployment.sh new file mode 100644 index 0000000..b2d9c61 --- /dev/null +++ b/ansible_runner/templates/run_deployment.sh @@ -0,0 +1,7 @@ +#!/bin/ksh +HOME={{ ansible_runner_home }} +DEPLOYMENT_DIR=$HOME/{{ deployment.name }} + +cd $DEPLOYMENT_DIR && \ + git pull && \ + {{ ansible_runner_command }} diff --git a/backup/defaults/main.yml b/backup/defaults/main.yml new file mode 100644 index 0000000..31b1153 --- /dev/null +++ b/backup/defaults/main.yml @@ -0,0 +1,28 @@ +--- +backup_mail_to: "root@localhost" +backup_mail_from: "backup" + +backup_user: "root" +backup_password: "BACKUP PASSWORD" + +backup_directories: + - /home + - /etc + - /var + +backup_destination: "sftp:user@host:/path/to/restic-repo" + +backup_throttle: 2 + +backup_keep_policy: + daily: 7 + weekly: 5 + monthly: 12 + yearly: 1 + +backup_pre_commands: + - rcctl stop gitea gitdaemon + +backup_post_commands: + - rcctl start gitdaemon gitea + diff --git a/backup/filter_plugins/backup_config.py b/backup/filter_plugins/backup_config.py new file mode 100644 index 0000000..a3d987c --- /dev/null +++ b/backup/filter_plugins/backup_config.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +class FilterModule(object): + def filters(self): + return { + 'parse_backup_destination': self.parse_backup_destination + } + + def parse_backup_destination(self, backup_destination): + """ + Parse restic backup destination. + + Args: + backup_destination (str): Bbackup destination. + Returns: + dict: Parsed backup destination. + """ + backup_config = {} + backup_config['protocol'] = None + backup_config['connection_string'] = None + backup_config['path'] = None + supported_protocols = ('sftp', 'local') + + if ':' in backup_destination: + dest_parts = backup_destination.split(':') + backup_config['protocol'] = dest_parts[0] + backup_config['connection_string'] = "".join(dest_parts[1:-1]) + backup_config['path'] = dest_parts[-1] + else: + backup_config['protocol'] = 'local' + backup_config['connection_string'] = None + backup_config['path'] = backup_destination + if backup_config['protocol'] not in supported_protocols: + raise ValueError("Unsupported backup destination") + + return backup_config diff --git a/backup/tasks/main.yml b/backup/tasks/main.yml new file mode 100644 index 0000000..f51875e --- /dev/null +++ b/backup/tasks/main.yml @@ -0,0 +1,66 @@ +--- +- name: generate backup config from destination + set_fact: + backup_config: "{{ backup_destination | parse_backup_destination }}" + +- name: generate ssh key for root if sftp backup + become: yes + openssh_keypair: + path: /root/.ssh/id_rsa + when: backup_config.protocol == 'sftp' + +- name: try to add backup server to known hosts + become: yes + command: 'ssh -o StrictHostKeyChecking=accept-new {{ backup_config.connection_string }} echo ok' + when: backup_config.protocol == 'sftp' + failed_when: false + +- name: ensure restic is installed + become: yes + package: + name: restic + state: latest + when: ansible_distribution|lower != 'openbsd' + +- name: ensure restic is installed + become: yes + community.general.openbsd_pkg: + name: restic + state: latest + snapshot: "{{ force_openbsd_snapshot|default(false) }}" + when: ansible_distribution|lower == 'openbsd' + +- name: copy backup password file to remote host + become: yes + copy: + content: "{{ backup_password }}" + dest: "{{ backup_password_file }}" + mode: "0400" + owner: "{{ backup_user }}" + +- name: template backup script + become: yes + template: + src: "backup.sh" + dest: "{{ backup_script_path }}" + owner: "{{ backup_user }}" + mode: "0700" + +- name: create backup repository if it does not exist already + become: yes + shell: "{{ backup_init_command }}" + changed_when: "'created restic repositroy' in backup_init_task.stdout" + failed_when: "'config file already exists' not in backup_init_task.stderr and backup_init_task.rc != 0" + register: backup_init_task + +- name: run backup + become: yes + shell: "{{ backup_job }}" + throttle: "{{ backup_throttle }}" + when: do_backup | default(false) + +- name: run cleanup + become: yes + shell: "{{ backup_cleanup_job }}" + throttle: "{{ backup_throttle }}" + when: do_backup | default(false) diff --git a/backup/templates/backup.sh b/backup/templates/backup.sh new file mode 100644 index 0000000..9601d70 --- /dev/null +++ b/backup/templates/backup.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +failed_backups=0 + +echo "starting backup at $(date)" +{% for pre_cmd in backup_pre_commands %} +echo "executing backup pre command: {{ pre_cmd }}" + +{{ pre_cmd }} +if [ $? -ne 0 ]; then + >&2 echo "pre command failed. aborting backup." + exit 1 +fi +{% endfor %} + +echo "---" + +{% for backup_directory in backup_directories %} +echo "backing up: {{ backup_directory }}" +{{ backup_command }} {{ backup_directory }} + +if [[ $? != 0 ]]; then + ((failed_backups=failed_backups+1)) + echo "error: backup failed" +fi + +echo "---" +{% endfor %} + +{% for post_cmd in backup_post_commands %} +echo "executing backup post command: {{ post_cmd }}" +{{ post_cmd }} +{% endfor %} + +echo "finished backup at $(date)" +echo "failed backups: $failed_backups" diff --git a/backup/vars/main.yml b/backup/vars/main.yml new file mode 100644 index 0000000..321cbc9 --- /dev/null +++ b/backup/vars/main.yml @@ -0,0 +1,11 @@ +--- +backup_restic_paths: + openbsd: /usr/local/bin/restic +backup_restic_path: "{{ backup_restic_paths[ansible_distribution|lower]|default('restic') }}" +backup_password_file: /etc/backup_password +backup_script_path: "/usr/local/bin/backup.sh" +backup_command: "{{ backup_restic_path }} -r {{ backup_destination }} -p {{ backup_password_file }} backup" +backup_init_command: "{{ backup_restic_path }} -r {{ backup_destination }} -p {{ backup_password_file }} init" +backup_cleanup_command: "{{ backup_restic_path }} -r {{ backup_destination }} -p {{ backup_password_file }} forget --keep-daily {{ backup_keep_policy.daily }} --keep-weekly {{ backup_keep_policy.weekly }} --keep-monthly {{ backup_keep_policy.monthly }} --keep-yearly {{ backup_keep_policy.yearly }}" +backup_job: "{{ backup_script_path }} | mail -s 'Backup report' -r backup {{ backup_mail_to }}" +backup_cleanup_job: "{{ backup_cleanup_command }} | mail -s 'Backup cleanup report' -r {{ backup_mail_from }} {{ backup_mail_to }}" diff --git a/backup_server/defaults/main.yml b/backup_server/defaults/main.yml new file mode 100644 index 0000000..6683fda --- /dev/null +++ b/backup_server/defaults/main.yml @@ -0,0 +1,4 @@ +backup_server_user: _backup +backup_server_home: /data/backup +backup_server_authorized_keys: +- "ssh-rsa...." diff --git a/backup_server/tasks/main.yml b/backup_server/tasks/main.yml new file mode 100644 index 0000000..8423bd4 --- /dev/null +++ b/backup_server/tasks/main.yml @@ -0,0 +1,11 @@ +- name: create backup user + become: yes + user: + name: "{{ backup_server_user }}" + home: "{{ backup_server_home }}" +- name: edit authorized_keys + become: yes + authorized_key: + user: "{{ backup_server_user }}" + state: present + key: "{{ backup_server_authorized_keys | join('\n') }}" diff --git a/bootstrap/defaults/main.yml b/bootstrap/defaults/main.yml new file mode 100644 index 0000000..acae56a --- /dev/null +++ b/bootstrap/defaults/main.yml @@ -0,0 +1,49 @@ +bootstrap_hostname: "{{ ansible_hostname }}" +bootstrap_domain: "{{ ansible_domain }}" + +bootstrap_shell: + ubuntu: /bin/bash + openbsd: /bin/ksh + alpine: /bin/ash + archlinux: /bin/bash + +bootstrap_groups: + ubuntu: sudo + openbsd: wheel + alpine: wheel + archlinux: wheel + + +bootstrap_users: + - name: ansible + shell: "{{ bootstrap_shell[ansible_distribution|lower] }}" + groups: "{{ bootstrap_groups[ansible_distribution|lower] }}" + state: present + authorized_keys: + - "{{ lookup('file', ansible_ssh_public_key_file) }}" + +bootstrap_packages: + ubuntu: + - name: tcpdump + state: present + - name: htop + state: present + - name: tmux + state: present + - name: strace + state: present + - name: postfix + state: present + - name: mailutils + state: present + openbsd: + - name: vim--no_x11 + state: present + alpine: + - name: vim + state: present + archlinux: + - name: vim + state: present + +bootstrap_root_mail: root@localhost diff --git a/bootstrap/handlers/main.yml b/bootstrap/handlers/main.yml new file mode 100644 index 0000000..9b6fdb8 --- /dev/null +++ b/bootstrap/handlers/main.yml @@ -0,0 +1,12 @@ +- name: restart sshd + become: yes + service: + name: "{{ bootstrap_ssh_service_name[ansible_distribution|lower] }}" + state: restarted + +- name: reload facts + setup: + +- name: bootstrap_reload_aliases + become: yes + command: "{{ bootstrap_aliases_reload_command[ansible_distribution|lower] }}" diff --git a/bootstrap/tasks/alpine.yml b/bootstrap/tasks/alpine.yml new file mode 100644 index 0000000..56a31a1 --- /dev/null +++ b/bootstrap/tasks/alpine.yml @@ -0,0 +1,20 @@ +- name: Upgrade / replace / downgrade / uninstall all installed packages to the latest versions available + community.general.apk: + available: yes + upgrade: yes + update_cache: yes + +- name: install doas + community.general.apk: + name: doas + state: latest + +- name: edit doas.conf + lineinfile: + line: 'permit nopass keepenv :wheel' + regexp: '^.*permit nopass keepenv :wheel.*$' + path: /etc/doas.conf + create: yes + owner: root + group: wheel + mode: 0600 diff --git a/bootstrap/tasks/archlinux.yml b/bootstrap/tasks/archlinux.yml new file mode 100644 index 0000000..20de63a --- /dev/null +++ b/bootstrap/tasks/archlinux.yml @@ -0,0 +1,26 @@ +- name: Upgrade / replace / downgrade / uninstall all installed packages to the latest versions available + community.general.pacman: + upgrade: yes + update_cache: yes + +- name: install doas + community.general.pacman: + name: opendoas + state: latest + +- name: edit doas.conf + lineinfile: + line: 'permit nopass keepenv :wheel' + regexp: '^.*permit nopass keepenv :wheel.*$' + path: /etc/doas.conf + create: yes + owner: root + group: wheel + mode: 0600 + +# currently broken; does not find hostnamectl binary +- name: set hostname (via systemd) + hostname: + name: "{{ bootstrap_hostname }}.{{ bootstrap_domain }}" + use: systemd + ignore_errors: yes diff --git a/bootstrap/tasks/common.yml b/bootstrap/tasks/common.yml new file mode 100644 index 0000000..7eba93e --- /dev/null +++ b/bootstrap/tasks/common.yml @@ -0,0 +1,41 @@ +- name: manage users + user: + name: "{{ user.name }}" + state: "{{ user.state|default('present') }}" + groups: "{{ user.groups }}" + shell: "{{ user.shell|default('/bin/bash') }}" + loop: "{{ bootstrap_users }}" + loop_control: + loop_var: user + +- name: manage authorized_keys + authorized_key: + user: "{{ user.name }}" + state: "{{ user.state }}" + key: "{{ user.authorized_keys | join('\n') }}" + loop: "{{ bootstrap_users }}" + loop_control: + loop_var: user + +- name: disable ssh password logins + lineinfile: + path: "{{ bootstrap_sshd_config[ansible_distribution|lower] }}" + regex: ^(# *)?PasswordAuthentication + line: PasswordAuthentication no + notify: restart sshd + +- name: disable ssh root login + lineinfile: + path: "{{ bootstrap_sshd_config[ansible_distribution|lower] }}" + regex: ^(# *)?PermitRootLogin + line: PermitRootLogin no + notify: restart sshd + +- name: setup alias for root mails + lineinfile: + path: "{{ bootstrap_aliases_file[ansible_distribution|lower] }}" + regex: '^( *)?root:.*$' + line: "root: {{ bootstrap_root_mail }}" + register: bootstrap_mail_alias + notify: bootstrap_reload_aliases + when: "ansible_distribution|lower in bootstrap_aliases_file" diff --git a/bootstrap/tasks/main.yml b/bootstrap/tasks/main.yml new file mode 100644 index 0000000..2ad67fc --- /dev/null +++ b/bootstrap/tasks/main.yml @@ -0,0 +1,12 @@ +- name: gather facts + setup: + +- name: run distribution specific include taks + include_tasks: "{{ ansible_distribution|lower}}.yml" + vars: + ansible_become: "{{ 'no' if ansible_ssh_user | default('None') == 'root' else 'yes' }}" + +- name: run common bootstrap tasks + include_tasks: common.yml + vars: + ansible_become: "{{ 'no' if ansible_ssh_user | default('None') == 'root' else 'yes' }}" diff --git a/bootstrap/tasks/openbsd.yml b/bootstrap/tasks/openbsd.yml new file mode 100644 index 0000000..1d9a3ac --- /dev/null +++ b/bootstrap/tasks/openbsd.yml @@ -0,0 +1,41 @@ +- name: edit doas.conf + lineinfile: + line: 'permit nopass keepenv :wheel' + regexp: '^.*permit nopass keepenv :wheel.*$' + path: /etc/doas.conf + create: yes + owner: root + group: wheel + mode: 0600 + +- name: Check for available syspatches + shell: syspatch -c + register: syspatch + changed_when: syspatch.stdout_lines|length > 0 + ignore_errors: yes + +- name: Install available syspatches + shell: syspatch + when: syspatch.changed + register: syspatch_install + until: syspatch_install.rc == 0 + retries: 5 + delay: 10 + +- name: reboot + reboot: + when: syspatch.changed + +- name: update installed packages + community.general.openbsd_pkg: + name: "*" + state: latest + snapshot: "{{ force_openbsd_snapshot | default(false) }}" + +- name: install bootstrap packages + community.general.openbsd_pkg: + name: "{{ package.name }}" + state: "{{ package.state }}" + loop: "{{ bootstrap_packages[ansible_distribution|lower] }}" + loop_control: + loop_var: package diff --git a/bootstrap/tasks/ubuntu.yml b/bootstrap/tasks/ubuntu.yml new file mode 100644 index 0000000..2a282a3 --- /dev/null +++ b/bootstrap/tasks/ubuntu.yml @@ -0,0 +1,21 @@ +- name: refresh apt cache and update packages + apt: + name: "*" + state: latest + update_cache: yes + +- name: manage packages + apt: + name: "{{ package.name }}" + state: "{{ package.state }}" + loop: "{{ bootstrap_packages[ansible_distribution|lower] }}" + loop_control: + loop_var: package + +- name: edit sudoers + lineinfile: + dest: /etc/sudoers + state: present + regexp: '^%sudo' + line: '%sudo ALL=(ALL) NOPASSWD: ALL' + validate: 'visudo -cf %s' diff --git a/bootstrap/vars/main.yml b/bootstrap/vars/main.yml new file mode 100644 index 0000000..0f86e8f --- /dev/null +++ b/bootstrap/vars/main.yml @@ -0,0 +1,20 @@ +--- +bootstrap_sshd_config: + ubuntu: /etc/ssh/sshd_config + openbsd: /etc/ssh/sshd_config + alpine: /etc/ssh/sshd_config + archlinux: /etc/ssh/sshd_config + +bootstrap_ssh_service_name: + ubuntu: sshd + openbsd: sshd + alpine: sshd + archlinux: sshd + +bootstrap_aliases_file: + openbsd: /etc/mail/aliases + ubuntu: /etc/aliases + +bootstrap_aliases_reload_command: + openbsd: smtpctl update table aliases + ubuntu: newaliases diff --git a/cronjobs/defaults/main.yml b/cronjobs/defaults/main.yml new file mode 100644 index 0000000..1eb471e --- /dev/null +++ b/cronjobs/defaults/main.yml @@ -0,0 +1,9 @@ +cronjobs: + - name: "hourly cronjob" + user: root + command: "echo Hi, I'm an hourly cronjob" + minute: "0" + hour: "*" + day: "*" + month: "*" + weekday: "*" diff --git a/cronjobs/tasks/main.yml b/cronjobs/tasks/main.yml new file mode 100644 index 0000000..aed70c4 --- /dev/null +++ b/cronjobs/tasks/main.yml @@ -0,0 +1,14 @@ +- name: setup cronjobs + become: yes + cron: + name: "{{ cronjob.name }}" + user: "{{ cronjob.user }}" + job: "{{ cronjob.command }}" + minute: "{{ cronjob.minute }}" + hour: "{{ cronjob.hour }}" + day: "{{ cronjob.day }}" + month: "{{ cronjob.month }}" + weekday: "{{ cronjob.weekday }}" + loop: "{{ cronjobs }}" + loop_control: + loop_var: cronjob diff --git a/data_sync/defaults/main.yml b/data_sync/defaults/main.yml new file mode 100644 index 0000000..eb45d04 --- /dev/null +++ b/data_sync/defaults/main.yml @@ -0,0 +1 @@ +data_sync_copy_links: False diff --git a/data_sync/tasks/main.yml b/data_sync/tasks/main.yml new file mode 100644 index 0000000..432501a --- /dev/null +++ b/data_sync/tasks/main.yml @@ -0,0 +1,19 @@ +--- +- name: install rsync + become: yes + package: + name: "{{ package }}" + state: present + loop: "{{ data_sync_packages[ansible_distribution|lower] }}" + loop_control: + loop_var: package +- name: synchronize data dir + become: yes + synchronize: + src: "{{ playbook_dir }}/data/" + dest: "/" + owner: no + group: no + perms: yes + rsync_path: '{{ ansible_become_method }} -u root rsync' + copy_links: '{{ data_sync_copy_links }}' diff --git a/data_sync/vars/main.yml b/data_sync/vars/main.yml new file mode 100644 index 0000000..887127a --- /dev/null +++ b/data_sync/vars/main.yml @@ -0,0 +1,3 @@ +data_sync_packages: + openbsd: + - rsync-3.2.3 diff --git a/dns_server/defaults/main.yml b/dns_server/defaults/main.yml new file mode 100644 index 0000000..fdca563 --- /dev/null +++ b/dns_server/defaults/main.yml @@ -0,0 +1,57 @@ +dns_zone_public: "mydomain.org" +dns_zone_local: "mydomain.local" +dns_server_public_ip: "{{ ansible_default_ipv4.address }}" +dns_server_local_ip: "127.0.0.1" +dns_zones: + - name: "{{ dns_zone_public }}" + role: "master" + reverse_zone: False + peers: "" + ttl: "2d" + slaves: + - 213.239.242.238 + - 213.133.105.6 + - 193.47.99.3 + soa: + - ns: "ns.{{ dns_zone_public }}." + mail: "admin.{{ dns_zone_public }}." + serial: "2018122520" + refresh: "1d" + retry: "1d" + expire: "4w" + ttl: "1h" + nameservers: + - "ns.{{ dns_zone_public }}." + records: + - name: "ns" + type: "A" + value: "{{ dns_server_public_ip }}" + - name: "*" + type: "A" + value: "{{ dns_server_public_ip }}" + - name: "vmhost" + type: "CNAME" + value: "ns" + - name: "{{ dns_zone_local }}" + role: "master" + reverse_zone: True + ttl: "2d" + slaves: + - "{{ dns_server_local_ip }}" + soa: + - ns: "ns.{{ dns_zone_local }}." + mail: "admin.{{ dns_zone_public }}." + serial: "2018121520" + refresh: "1d" + retry: "1d" + expire: "4w" + ttl: "1h" + nameservers: + - "ns.{{ dns_zone_local }}" + records: + - name: "ns" + type: "A" + value: "{{ dns_server_local_ip }}" + - name: "git" + type: "A" + value: "10.1.0.10" diff --git a/dns_server/handlers/main.yml b/dns_server/handlers/main.yml new file mode 100644 index 0000000..649a96a --- /dev/null +++ b/dns_server/handlers/main.yml @@ -0,0 +1,19 @@ +- name: reload nsd + become: yes + service: + name: nsd + state: reloaded + enabled: true +- name: reload unbound + become: yes + service: + name: nsd + state: reloaded + enabled: true +- name: reload zonefiles + become: yes + command: nsd-control reload + notify: notify slaves +- name: notify slaves + become: yes + command: nsd-control notify diff --git a/dns_server/tasks/main.yml b/dns_server/tasks/main.yml new file mode 100644 index 0000000..161ddef --- /dev/null +++ b/dns_server/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- name: OpenBSD dns + include_tasks: openbsd.yml + when: ansible_distribution|lower == 'openbsd' + vars: + ansible_become: yes diff --git a/dns_server/tasks/openbsd.yml b/dns_server/tasks/openbsd.yml new file mode 100644 index 0000000..693f53f --- /dev/null +++ b/dns_server/tasks/openbsd.yml @@ -0,0 +1,44 @@ +--- +- name: unbound.conf + template: + src: unbound.conf + dest: /var/unbound/etc/unbound.conf + owner: root + group: wheel + mode: 0644 + notify: reload unbound +- name: nsd.conf + template: + src: nsd.conf + dest: /var/nsd/etc/nsd.conf + owner: root + group: _nsd + mode: 0640 + notify: reload nsd +- name: forward zonefile(s) + template: + src: zonefile.forward + dest: "/var/nsd/zones/{{ item.role }}/{{ item.name }}" + owner: root + group: _nsd + mode: 0640 + loop: "{{ dns_zones }}" + notify: reload zonefiles + +- name: check zone files + shell: "nsd-checkzone {{ item.name }} /var/nsd/zones/{{ item.role }}/{{ item.name }}" + register: zone_check + failed_when: zone_check.rc != 0 + changed_when: False + loop: "{{ dns_zones }}" + +- name: nsd started and enabled + service: + name: nsd + state: started + enabled: true +- name: unbound started and enabled + service: + name: unbound + state: started + enabled: true diff --git a/dns_server/templates/nsd.conf b/dns_server/templates/nsd.conf new file mode 100644 index 0000000..86b5c05 --- /dev/null +++ b/dns_server/templates/nsd.conf @@ -0,0 +1,39 @@ +# $OpenBSD: nsd.conf,v 1.13 2018/08/16 17:59:12 florian Exp $ + +server: + hide-version: yes + verbosity: 1 + database: "" # disable database + +remote-control: + control-enable: yes + control-interface: /var/run/nsd.sock + +## tsig key example +#key: +# name: "tsig1.example.com." +# algorithm: hmac-sha256 +# secret: "bWVrbWl0YXNkaWdvYXQ=" + +{% for zone in dns_zones %} +zone: + name: "{{ zone.name }}" + zonefile: "{{ zone.role }}/{{ zone.name }}" +{% if zone.role == "master" %} +{% for slave in zone.slaves %} + notify: {{ slave }} NOKEY + provide-xfr: {{ slave }} NOKEY +{% endfor %} +{% elif zone.role == "slave" %} +# allow-notify: 192.0.2.2 tsig1.example.com. +# request-xfr: 192.0.2.2 tsig1.example.com. +{% endif %} +{% endfor %} + +## slave zone example +#zone: +# name: "example.net" +# zonefile: "slave/example.net" +# allow-notify: 192.0.2.2 tsig1.example.com. +# request-xfr: 192.0.2.2 tsig1.example.com. + diff --git a/dns_server/templates/unbound.conf b/dns_server/templates/unbound.conf new file mode 100644 index 0000000..77c839e --- /dev/null +++ b/dns_server/templates/unbound.conf @@ -0,0 +1,46 @@ +# $OpenBSD: unbound.conf,v 1.8 2018/03/29 20:40:22 florian Exp $ + +server: + interface: 127.0.0.1@5353 # listen on alternative port + interface: ::1@5353 + + access-control: 0.0.0.0/0 allow + access-control: 127.0.0.0/8 allow + access-control: ::0/0 refuse + access-control: ::1 allow + + hide-identity: yes + hide-version: yes + + auto-trust-anchor-file: "/var/unbound/db/root.key" +{% for zone in dns_zones %} + domain-insecure: "{{ zone.name }}" +{% endfor %} + +remote-control: + control-enable: yes + control-use-cert: no + control-interface: /var/run/unbound.sock + + +{% for zone in dns_zones %} +stub-zone: + name: "{{ zone.name }}" + stub-addr: "{{ dns_server_public_ip }}" +{% endfor %} + +stub-zone: + name: "10.in-addr.arpa" + stub-addr: "{{ dns_server_public_ip }}" +stub-zone: + name: "168.192.in-addr.arpa" + stub-addr: "{{ dns_server_public_ip }}" + +forward-zone: + name: "." # use for ALL queries + forward-addr: 74.82.42.42 # he.net + forward-addr: 2001:470:20::2 # he.net v6 + forward-addr: 8.8.8.8 # google.com + forward-addr: 2001:4860:4860::8888 # google.com v6 + forward-addr: 208.67.222.222 # opendns.com + forward-first: yes # try direct if forwarder fails diff --git a/dns_server/templates/zonefile.forward b/dns_server/templates/zonefile.forward new file mode 100644 index 0000000..4c99a20 --- /dev/null +++ b/dns_server/templates/zonefile.forward @@ -0,0 +1,21 @@ +$ORIGIN {{ item.name }}. +$TTL {{ item.ttl }} +@ IN SOA {{ item.soa.0.ns }} {{ item.soa.0.mail }} ( + {{ item.soa.0.serial }} ; serial + {{ item.soa.0.refresh }} ; refresh + {{ item.soa.0.retry }} + {{ item.soa.0.expire }} ; expire + {{ item.soa.0.ttl }} ; ttl + ) +; Name servers +{% for ns in item.nameservers %} +@ IN NS {{ ns }} +{% endfor %} + +{% for record in item.records %} +{% if record.type == 'TXT' %} +{{ record.name }} IN {{ record.type }} "{{ record.value }}" +{% else %} +{{ record.name }} IN {{ record.type }} {{ record.value }} +{% endif %} +{% endfor %} diff --git a/dns_server/templates/zonefile.reverse b/dns_server/templates/zonefile.reverse new file mode 100644 index 0000000..f5e99af --- /dev/null +++ b/dns_server/templates/zonefile.reverse @@ -0,0 +1,17 @@ +$ORIGIN {{ item.name }}. +$TTL {{ item.ttl }} +@ IN SOA {{ item.soa.ns }} {{ item.soa.mail }} ( + {{ date }} ; serial + {{ item.soa.refresh }} ; refresh + {{ item.soa.retry }} + {{ item.soa.expire }} ; expire + {{ item.soa.ttl }} ; ttl + ) +; Name servers +{% for ns in item.nameservers %} +@ IN NS {{ ns }} +{% endfor %} + +{% for record in item.records %} +{{ record.name }} IN {{ record.type }} {{ record.value }} +{% endfor %} diff --git a/firewall/defaults/main.yml b/firewall/defaults/main.yml new file mode 100644 index 0000000..eee1b2f --- /dev/null +++ b/firewall/defaults/main.yml @@ -0,0 +1,13 @@ +firewall_tcp_services: + - 80 + - 443 +firewall_udp_services: + - 53 +firewall_max_ssh_src_conn: "35" +firewall_max_ssh_src_conn_rate: "25/5" +firewall_max_tcp_src_conn: "150" +firewall_max_tcp_src_conn_rate: "100/5" + +firewall_whitelist_enable: false +firewall_whitelist: + - 127.0.0.1 diff --git a/firewall/files/facts.d-openbsd/tcp_services.fact b/firewall/files/facts.d-openbsd/tcp_services.fact new file mode 100755 index 0000000..bfcfce0 --- /dev/null +++ b/firewall/files/facts.d-openbsd/tcp_services.fact @@ -0,0 +1,15 @@ +#!/bin/ksh + +exposed_tcp_in=$(netstat -l -n -finet -ptcp |\ + awk '$4 !~ /^127\.0\.0\.1.*$/ && $1 == "tcp" {print $4}') + +output="" +if [ ! -z "$exposed_tcp_in" ]; then + output=$output"[ " + for i in $exposed_tcp_in; do + port="${i##*.}" + output="$output\"$port\"," + done + output=${output%?}" ]" +fi +echo $output diff --git a/firewall/files/facts.d-openbsd/udp_services.fact b/firewall/files/facts.d-openbsd/udp_services.fact new file mode 100755 index 0000000..d7af51f --- /dev/null +++ b/firewall/files/facts.d-openbsd/udp_services.fact @@ -0,0 +1,15 @@ +#!/bin/ksh + +exposed_udp_in=$(netstat -l -n -finet -pudp |\ + awk '$4 !~ /^127\.0\.0\.1.*$/ && $1 == "udp" {print $4}') + +output="" +if [ ! -z "$exposed_udp_in" ]; then + output=$output"[ " + for i in $exposed_udp_in; do + port="${i##*.}" + output="$output\"$port\"," + done + output=${output%?}" ]" +fi +echo $output diff --git a/firewall/files/tcp_services.fact b/firewall/files/tcp_services.fact new file mode 100755 index 0000000..c5062c0 --- /dev/null +++ b/firewall/files/tcp_services.fact @@ -0,0 +1,17 @@ +#!/bin/ksh +ports=$(netstat -lnptcp -finet | awk '{ print $4 }' |grep '\.' | sed 's/*./0.0.0.0./g' | grep -v '127\.0\.0\.1' | cut -f 5 -d '.' | sort | uniq) +ports_len=$(echo $ports | awk '{ print NF - 1 }') + +echo "[ " + +i=0 +for port in $ports; do + if [[ $i -lt $ports_len ]]; then + echo " \"$port\"," + else + echo " \"$port\"" + fi + ((i=i+1)) +done + +echo " ]" diff --git a/firewall/handlers/main.yml b/firewall/handlers/main.yml new file mode 100644 index 0000000..4c1db90 --- /dev/null +++ b/firewall/handlers/main.yml @@ -0,0 +1,16 @@ +--- +- name: reload facts + setup: +- name: reload pf for real + shell: pfctl -f /etc/pf.conf + become: yes +- name: reload pf + shell: pfctl -nf /etc/pf.conf + notify: reload pf for real + become: yes +- name: reload network + shell: sh /etc/netstart + become: yes +- name: iptables-save-ubuntu + command: netfilter-persistent save + become: yes diff --git a/firewall/tasks/main.yml b/firewall/tasks/main.yml new file mode 100644 index 0000000..a593f1b --- /dev/null +++ b/firewall/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- name: OpenBSD pf + include_tasks: openbsd.yml + when: ansible_distribution|lower == 'openbsd' + vars: + ansible_become: yes diff --git a/firewall/tasks/openbsd.yml b/firewall/tasks/openbsd.yml new file mode 100644 index 0000000..3977503 --- /dev/null +++ b/firewall/tasks/openbsd.yml @@ -0,0 +1,127 @@ +--- +- name: deploy custom facts + copy: + src: "{{ item }}" + dest: /etc/ansible/facts.d/ + mode: 0755 + with_fileglob: + - facts.d-openbsd/* + notify: reload facts + +- name: update firewall whitelist + lineinfile: + line: '{{ item }}' + regexp: '^.*{{ item }}.*$' + path: /etc/pf.whitelist + create: yes + loop: "{{ firewall_whitelist }}" + when: firewall_whitelist_enable + +- meta: flush_handlers +- name: anchor directory + file: + path: "/etc/anchors" + state: "directory" +- name: ansible pf anchor + copy: + dest: "/etc/anchors/ansible" + content: "" + force: no + owner: "root" + mode: "0600" +- name: custom pf anchor + copy: + dest: "/etc/anchors/custom" + force: no + content: "" + owner: "root" + mode: "0600" +- name: create pf-badhost user + user: + name: "{{ pfbadhost_user }}" + shell: /sbin/nologin + home: /var/empty + create_home: no +- name: install ripgrep and mawk + community.general.openbsd_pkg: + name: [ "ripgrep", "mawk" ] + state: present + snapshot: "{{ force_openbsd_snapshot | default(false) }}" +- name: download pf-badhost + get_url: + url: "{{ pfbadhost_url }}" + dest: "{{ pfbadhost_path }}" + owner: root + group: wheel + mode: "0755" + register: pfbadhost_installed + +- name: enable authlog scanning + lineinfile: + path: "{{ pfbadhost_path }}" + regexp: '^\s+_HAIL_MARY=[01].*$' + line: '_HAIL_MARY=1' + changed_when: false + +- name: set doas permissions for pf-badhost + lineinfile: + path: /etc/doas.conf + regexp: "^{{ doas_line }}$" + line: "{{ doas_line }}" + loop: + - "permit nopass {{ pfbadhost_user }} cmd /sbin/pfctl args -nf /etc/pf.conf" + - "permit nopass {{ pfbadhost_user }} cmd /sbin/pfctl args -t pfbadhost -T replace -f /etc/pf-badhost.txt" + - "permit nopass {{ pfbadhost_user }} cmd /usr/bin/zcat args -f /var/log/authlog /var/log/authlog.0.gz" + loop_control: + loop_var: doas_line +- name: create pf-badhost log dir + file: + path: /var/log/pf-badhost + state: directory + owner: root + group: wheel + mode: "0755" +- name: create required files for pf-badhost + copy: + content: "" + dest: "{{ pfbadhost_required_file }}" + owner: "{{ pfbadhost_user }}" + group: wheel + mode: "0640" + force: no + loop: + - /etc/pf-badhost.txt + - /var/log/pf-badhost/pf-badhost.log + - /var/log/pf-badhost/pf-badhost.log.0.gz + loop_control: + loop_var: pfbadhost_required_file +- name: ensure permission for pf-badhost + file: + path: "{{ pfbadhost_required_file }}" + owner: "{{ pfbadhost_user }}" + group: wheel + mode: "0640" + loop: + - /etc/pf-badhost.txt + - /var/log/pf-badhost/pf-badhost.log + - /var/log/pf-badhost/pf-badhost.log.0.gz + loop_control: + loop_var: pfbadhost_required_file +- name: setup pf-badhost cronjob + cron: + name: "update pf-badhosts" + user: "{{ pfbadhost_user }}" + job: "-s pf-badhost -O openbsd" + minute: "~" + hour: "0~1" +- name: run pf badhosts + command: "doas -u {{ pfbadhost_user }} pf-badhost -O openbsd" + when: pfbadhost_installed.changed +- name: pf.conf + template: + src: pf.conf + dest: /etc/pf.conf + owner: root + group: wheel + mode: '0600' + notify: reload pf diff --git a/firewall/templates/pf.conf b/firewall/templates/pf.conf new file mode 100644 index 0000000..ff24bc2 --- /dev/null +++ b/firewall/templates/pf.conf @@ -0,0 +1,54 @@ +# Options +set skip on lo + +# Macros and Tables +table persist +{% if firewall_whitelist_enable %} +table persist file "/etc/pf.whitelist" +{% endif %} +table persist file "/etc/pf-badhost.txt" +{% if firewall_tcp_services|length > 1 %} +tcp_in = "{ {% for port in firewall_tcp_services %} {{ port }} {% endfor %} }" +{% endif %} + +{% if firewall_udp_services|length > 1 %} +udp_in = "{ {% for port in firewall_udp_services %} {{ port }} {% endfor %} }" +{% endif %} + +{% if firewall_whitelist_enable %} +pass in quick from +{% endif %} +block in quick on egress from +block out quick on egress to + +# Quick rules +pass in quick proto tcp to port ssh flags S/SA keep state \ + (max-src-conn {{ firewall_max_ssh_src_conn }}, \ + max-src-conn-rate {{ firewall_max_ssh_src_conn_rate }}, \ + overload flush) + +pass in quick inet proto icmp icmp-type echoreq + +# Ruleset +block log +pass out on egress +block in quick log from + +{% if firewall_tcp_services|length > 1 %} +pass in proto tcp to port $tcp_in flags S/SA keep state \ + (max-src-conn {{ firewall_max_tcp_src_conn }}, \ + max-src-conn-rate {{ firewall_max_tcp_src_conn_rate }}, \ + overload flush) +{% endif %} + +{% if firewall_udp_services|length > 1 %} +pass in proto udp to port $udp_in +{% endif %} + +# Ansible Ruleset +anchor ansible +load anchor ansible from "/etc/anchors/ansible" + +# Custom Rules +anchor custom +load anchor custom from "/etc/anchors/custom" diff --git a/firewall/vars/main.yml b/firewall/vars/main.yml new file mode 100644 index 0000000..1fdea30 --- /dev/null +++ b/firewall/vars/main.yml @@ -0,0 +1,3 @@ +pfbadhost_user: _pfbadhost +pfbadhost_url: https://geoghegan.ca/pub/pf-badhost/0.5/pf-badhost.sh +pfbadhost_path: /usr/local/bin/pf-badhost diff --git a/gitea/defaults/main.yml b/gitea/defaults/main.yml new file mode 100644 index 0000000..208b46e --- /dev/null +++ b/gitea/defaults/main.yml @@ -0,0 +1,8 @@ +gitea_fqdn: "{{ ansible_fqdn }}" +gitea_httpd: True +gitea_admins: + - name: gitea_admin + email: root@localhost + password: CHANGEME +gitea_tls_cert: "{{ webserver_tls_cert|default(false) }}" +gitea_tls_key: "{{ webserver_tls_key|default(false) }}" diff --git a/gitea/handlers/main.yml b/gitea/handlers/main.yml new file mode 100644 index 0000000..2714e41 --- /dev/null +++ b/gitea/handlers/main.yml @@ -0,0 +1,10 @@ +- name: restart_gitea + service: + name: gitea + state: restarted + become: yes +- name: restart_httpd + service: + name: httpd + state: restarted + become: yes diff --git a/gitea/tasks/common.yml b/gitea/tasks/common.yml new file mode 100644 index 0000000..6f4caf5 --- /dev/null +++ b/gitea/tasks/common.yml @@ -0,0 +1,96 @@ +--- +- name: "install package: {{ package }}" + package: + name: "{{ package }}" + state: latest + loop: "{{ gitea_packages[ ansible_distribution|lower ] }}" + loop_control: + loop_var: package + when: ansible_distribution|lower != "openbsd" + +- name: "install package: {{ package }}" + community.general.openbsd_pkg: + name: "{{ package }}" + state: latest + snapshot: "{{ force_openbsd_snapshot|default(false) }}" + loop: "{{ gitea_packages[ ansible_distribution|lower ] }}" + loop_control: + loop_var: package + when: ansible_distribution|lower == "openbsd" + +- name: set groups + user: + name: "{{ user.user }}" + groups: "{{ user.groups }}" + append: yes + loop: "{{ gitea_groups[ ansible_distribution|lower ] }}" + loop_control: + loop_var: user + +- name: set gitea permission + file: + path: "{{ file.path }}" + mode: "{{ file.mode }}" + state: "{{ file.state }}" + loop: "{{ gitea_permissions[ ansible_distribution|lower ] }}" + loop_control: + loop_var: file + +- name: "edit ini files" + ini_file: + path: "{{ config.path }}" + section: "{{ config.section }}" + option: "{{ config.option }}" + value: "{{ config.value }}" + loop: "{{ gitea_ini_values[ ansible_distribution|lower ] }}" + loop_control: + loop_var: config + notify: restart_gitea +- name: "ensure {{ cfg.line }} is in {{ cfg.path }}" + lineinfile: + path: "{{ cfg.path }}" + line: "{{ cfg.line }}" + regexp: "{{ cfg.regexp }}" + loop: "{{ gitea_config_insertions[ ansible_distribution|lower ] }}" + loop_control: + loop_var: cfg + notify: restart_gitea + +- name: "template {{ cfg.path }}" + template: + src: "{{ cfg.template }}" + dest: "{{ cfg.path }}" + loop: "{{ gitea_config_templates[ ansible_distribution|lower ] }}" + loop_control: + loop_var: cfg + notify: restart_httpd + when: gitea_httpd + +- name: create initialization lock file + copy: + dest: /etc/gitea/initialized + content: "" + register: gitea_init + +- name: "initialize database" + shell: doas -u _gitea gitea migrate -c /etc/gitea/app.ini + environment: "{{ gitea_environment[ ansible_distribution|lower ] }}" + when: gitea_init.changed + +- name: "create admin users" + shell: "doas -u _gitea gitea admin user create -c /etc/gitea/app.ini --admin --username {{ user.name }} --email {{ user.email }} --password {{ user.password }}" + register: gitea_user_data + when: gitea_init.changed + notify: restart_gitea + loop: "{{ gitea_admins }}" + loop_control: + loop_var: user + +- name: "start and enable: {{ service }}" + service: + name: "{{ service }}" + enabled: True + state: started + loop: "{{ gitea_services[ ansible_distribution|lower ] }}" + loop_control: + loop_var: service diff --git a/gitea/tasks/main.yml b/gitea/tasks/main.yml new file mode 100644 index 0000000..8a57d04 --- /dev/null +++ b/gitea/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- name: run common tasks + include_tasks: common.yml + vars: + ansible_become: yes + diff --git a/gitea/templates/dkim_signing.conf.j2 b/gitea/templates/dkim_signing.conf.j2 new file mode 100644 index 0000000..0fe0386 --- /dev/null +++ b/gitea/templates/dkim_signing.conf.j2 @@ -0,0 +1,8 @@ +allow_username_mismatch = true; + +domain { + {{ mailserver_domain }} { + path = "{{ mailserver_dkim.key }}"; + selector = "{{ mailserver_dkim.selector }}"; + } +} diff --git a/gitea/templates/httpd.conf.gitea.j2 b/gitea/templates/httpd.conf.gitea.j2 new file mode 100644 index 0000000..54e05c0 --- /dev/null +++ b/gitea/templates/httpd.conf.gitea.j2 @@ -0,0 +1,32 @@ +{% if gitea_tls_cert|default(false) %} +server "{{ gitea_fqdn }}" { + listen on * port 80 + location "/.well-known/acme-challenge/*" { + root "/acme" + request strip 2 + } + location * { + block return 302 "https://$HTTP_HOST$REQUEST_URI" + } + } + +server "{{ gitea_fqdn }}" { + listen on * tls port 443 + tls { + certificate "{{ gitea_tls_cert }}" + key "{{ gitea_tls_key }}" + } + connection { max requests 500, timeout 3600 } + location "*" { + fastcgi socket "/run/gitea.sock" + } +} +{% else %} +server "{{ gitea_fqdn }}" { + listen on * port 80 + connection { max requests 500, timeout 3600 } + location "*" { + fastcgi socket "/run/gitea.sock" + } +} +{% endif %} diff --git a/gitea/templates/smtpd.conf.j2 b/gitea/templates/smtpd.conf.j2 new file mode 100644 index 0000000..ce4c735 --- /dev/null +++ b/gitea/templates/smtpd.conf.j2 @@ -0,0 +1,32 @@ +pki {{ mailserver_fqdn }} cert "{{ mailserver_tls_cert }}" +pki {{ mailserver_fqdn }} key "{{ mailserver_tls_key }}" + +filter check_dyndns phase connect match rdns regex { '.*\.dyn\..*', '.*\.dsl\..*' } \ + disconnect "550 no residential connections" + +filter check_rdns phase connect match !rdns \ + disconnect "550 no rDNS is so 80s" + +filter check_fcrdns phase connect match !fcrdns \ + disconnect "550 no FCrDNS is so 80s" + +filter senderscore \ + proc-exec "filter-senderscore -blockBelow {{ mailserver_senderscore_block }} -junkBelow {{ mailserver_senderscore_junk }} -slowFactor 5000" + +filter rspamd proc-exec "filter-rspamd" + +table aliases file:/etc/mail/aliases + +listen on all tls pki {{ mailserver_fqdn }} \ + filter { check_dyndns, check_rdns, check_fcrdns, senderscore, rspamd } + +listen on all port submission tls-require pki {{ mailserver_fqdn }} auth filter rspamd + +action "local_mail" maildir junk alias +action "outbound" relay helo {{ mailserver_fqdn }} + +match from any for domain "{{ mailserver_domain }}" action "local_mail" +match for local action "local_mail" + +match from any auth for any action "outbound" +match for any action "outbound" diff --git a/gitea/vars/main.yml b/gitea/vars/main.yml new file mode 100644 index 0000000..b8effd7 --- /dev/null +++ b/gitea/vars/main.yml @@ -0,0 +1,62 @@ +gitea_http: "{{ 'http' if not gitea_tls_cert else 'https' }}" +gitea_environment: + openbsd: + HOME: /var/gitea + GITEA_WORK_DIR: /usr/local/share/gitea + GITEA_CUSTOM: /var/gitea/custom + USER: _gitea +gitea_groups: + openbsd: + - user: _gitea + groups: daemon +gitea_permissions: + openbsd: + - path: /var/www/run + mode: "0775" + state: directory +gitea_packages: + openbsd: + - gitea + +gitea_services: + openbsd: + - gitea + - gitdaemon + +gitea_ini_values: + openbsd: + - path: /etc/gitea/app.ini + section: security + option: INSTALL_LOCK + value: "true" + - path: /etc/gitea/app.ini + section: server + option: HTTP_ADDR + value: /var/www/run/gitea.sock + - path: /etc/gitea/app.ini + section: server + option: PROTOCOL + value: fcgi+unix + - path: /etc/gitea/app.ini + section: server + option: DOMAIN + value: "{{ gitea_fqdn }}" + - path: /etc/gitea/app.ini + section: server + option: ROOT_URL + value: "{{ gitea_http }}://{{ gitea_fqdn }}/" + - path: /etc/gitea/app.ini + section: server + option: LOCAL_ROOT_URL + value: "https://{{ gitea_fqdn }}/" +gitea_config_insertions: + openbsd: + - path: /etc/httpd.conf + line: 'include "/etc/httpd.conf.gitea"' + regexp: '^.*include.*"/etc/httpd.conf.gitea".*$' + + +gitea_config_templates: + openbsd: + - path: /etc/httpd.conf.gitea + template: httpd.conf.gitea.j2 diff --git a/icinga2/defaults/main.yml b/icinga2/defaults/main.yml new file mode 100644 index 0000000..ce26054 --- /dev/null +++ b/icinga2/defaults/main.yml @@ -0,0 +1,25 @@ +icinga2_admin_mail: root@localhost + +icinga2_features: + - api + - ido-mysql + +icinga2_mysql_auth: + host: 127.0.0.1 + user: root + password: CHANGEME + +icinga2_mysql_db: + name: icinga2 + user: icinga2 + password: CHANGEME + schema: /usr/share/icinga2-ido-mysql/schema/mysql.sql + schema_openbsd: /usr/local/share/icinga2-ido-mysql/schema/mysql.sql + +icinga2_api_users: + - name: root + password: CHANGEME + permissions: '[ "*" ]' + - name: icingaweb2 + password: CHANGEME + permissions: '[ "status/query", "actions/*", "objects/modify/*", "objects/query/*" ]' diff --git a/icinga2/files/commands/openbsd.conf b/icinga2/files/commands/openbsd.conf new file mode 100644 index 0000000..5d023a3 --- /dev/null +++ b/icinga2/files/commands/openbsd.conf @@ -0,0 +1,3 @@ +object CheckCommand "openbsd-services" { + command = [ PluginDir + "/check_services.sh" ] +} diff --git a/icinga2/files/downtimes.conf b/icinga2/files/downtimes.conf new file mode 100644 index 0000000..7449f20 --- /dev/null +++ b/icinga2/files/downtimes.conf @@ -0,0 +1,35 @@ +apply ScheduledDowntime "maintainance-downtime" to Host { + author = "icingaadmin" + comment = "Scheduled downtime for maintenance" + + ranges = { + monday = host.vars.maintenance_downtime + tuesday = host.vars.maintenance_downtime + wednesday = host.vars.maintenance_downtime + thursday = host.vars.maintenance_downtime + friday = host.vars.maintenance_downtime + saturday = host.vars.maintenance_downtime + sunday = host.vars.maintenance_downtime + } + + assign where host.vars.maintenance_downtime != "" + +} + +apply ScheduledDowntime "maintainance-downtime" to Service { + author = "icingaadmin" + comment = "Scheduled downtime for maintenance" + + ranges = { + monday = host.vars.maintenance_downtime + tuesday = host.vars.maintenance_downtime + wednesday = host.vars.maintenance_downtime + thursday = host.vars.maintenance_downtime + friday = host.vars.maintenance_downtime + saturday = host.vars.maintenance_downtime + sunday = host.vars.maintenance_downtime + } + + assign where host.vars.maintenance_downtime != "" + +} diff --git a/icinga2/files/notifications.conf b/icinga2/files/notifications.conf new file mode 100644 index 0000000..ce2be67 --- /dev/null +++ b/icinga2/files/notifications.conf @@ -0,0 +1,27 @@ +apply Notification "mail-icingaadmin" to Host { + import "mail-host-notification" + user_groups = host.vars.notification.mail.groups + users = host.vars.notification.mail.users + + interval = 0 + + types = [ Custom, Acknowledgement, Problem, Recovery, FlappingStart, FlappingEnd ] + + //vars.notification_logtosyslog = true + + assign where host.vars.notification.mail +} + +apply Notification "mail-icingaadmin" to Service { + import "mail-service-notification" + user_groups = host.vars.notification.mail.groups + users = host.vars.notification.mail.users + + interval = 0 + + types = [ Custom, Acknowledgement, Problem, Recovery, FlappingStart, FlappingEnd ] + + //vars.notification_logtosyslog = true + + assign where host.vars.notification.mail +} diff --git a/icinga2/files/services/haproxy_services.conf b/icinga2/files/services/haproxy_services.conf new file mode 100644 index 0000000..c50456e --- /dev/null +++ b/icinga2/files/services/haproxy_services.conf @@ -0,0 +1,8 @@ +apply Service "Haproxy Backends" { + import "generic-service" + check_command = "haproxy.pl" + vars += host.vars.backends + vars.haproxy_url = "https://" + host.name + ":" + vars.haproxy_port + "/csv" + + assign where host.vars.os == "haproxy" +} diff --git a/icinga2/files/services/http_services.conf b/icinga2/files/services/http_services.conf new file mode 100644 index 0000000..2dc2de8 --- /dev/null +++ b/icinga2/files/services/http_services.conf @@ -0,0 +1,29 @@ +apply Service "Zertifikat: " for ( vhost => config in host.vars.vhosts ) to Host { + import "generic-service" + + check_command = "http" + + vars.http_link = true + vars.http_certificate = 80 + vars.http_sni = true + vars.http_address = host.address + + vars += config + + assign where host.vars.vhosts[vhost]["http_ssl"] +} + +apply Service "HTTP(S): " for ( vhost => config in host.vars.vhosts ) to Host { + import "generic-service" + + check_command = "http" + + vars.http_link = true + + vars += config + + vars.http_address = host.address + + assign where host.vars.vhosts[vhost]["http_uri"] || host.vars.vhosts[vhost]["http_string"] || host.vars.vhosts[vhost]["http_pagesize"] +} + diff --git a/icinga2/files/services/tcp_services.conf b/icinga2/files/services/tcp_services.conf new file mode 100644 index 0000000..1849936 --- /dev/null +++ b/icinga2/files/services/tcp_services.conf @@ -0,0 +1,7 @@ +apply Service "tcp port " for ( port in host.vars.tcp_ipv4 ) to Host { + check_command = "tcp" + vars.tcp_ipv4 = "true" + vars.tcp_port = port + + assign where host.address +} diff --git a/icinga2/files/services/unix_services.conf b/icinga2/files/services/unix_services.conf new file mode 100644 index 0000000..733f97c --- /dev/null +++ b/icinga2/files/services/unix_services.conf @@ -0,0 +1,44 @@ +apply Service "" for ( disk => config in host.vars.disks ) to Host { + check_command = "disk" + vars += config + + import "byssh" + + assign where host.vars.os == "Linux" || host.vars.os == "OpenBSD" +} + +apply Service "process: " for ( proc => config in host.vars.procs ) to Host { + check_command = "procs" + vars += config + + import "byssh" + + assign where host.vars.os == "Linux" || host.vars.os == "OpenBSD" +} + +apply Service "load" { + check_command = "load" + vars += host.vars.load + + import "byssh" + + assign where host.vars.os == "Linux" || host.vars.os == "OpenBSD" +} + +apply Service "swap" { + check_command = "swap" + vars += host.vars.swap + + import "byssh" + + assign where host.vars.os == "Linux" || host.vars.os == "OpenBSD" +} + +apply Service "services" { + check_command = "openbsd-services" + + import "byssh" + + assign where host.vars.os == "OpenBSD" +} + diff --git a/icinga2/files/services/windows_services.conf b/icinga2/files/services/windows_services.conf new file mode 100644 index 0000000..e08916e --- /dev/null +++ b/icinga2/files/services/windows_services.conf @@ -0,0 +1,53 @@ +apply Service "Windows Disk: " for ( disk => config in host.vars.disks ) to Host { + check_command = "disk-windows" + vars += config + assign where host.vars.os == "windows" +} + +apply Service "Windows Process: " for ( proc => config in host.vars.procs ) to Host { + import "byagent" + check_command = "procs-windows" + vars += config + assign where host.vars.os == "windows" +} + +apply Service "Windows Serivces: " for ( service => config in host.vars.services ) to Host { + import "byagent" + check_command = "service-windows" + vars += config + assign where host.vars.os == "windows" +} + +apply Service "Windows CPU" { + import "byagent" + check_command = "load-windows" + vars += host.vars.load + assign where host.vars.os == "windows" +} + +apply Service "Windows Memory" { + import "byagent" + check_command = "memory-windows" + vars += host.vars.mem + assign where host.vars.os == "windows" +} + +apply Service "Windows Network" { + import "byagent" + check_command = "network-windows" +# vars += host.vars.net + assign where host.vars.os == "windows" +} + +apply Service "Windows Swap" { + import "byagent" + check_command = "swap-windows" +# vars += host.vars.swap + assign where host.vars.os == "windows" +} + +apply Service "Windows Update" { + import "byagent" + check_command = "update-windows" + assign where host.vars.os == "windows" +} diff --git a/icinga2/files/ssh_config b/icinga2/files/ssh_config new file mode 100644 index 0000000..1916379 --- /dev/null +++ b/icinga2/files/ssh_config @@ -0,0 +1,2 @@ +Host * + StrictHostKeyChecking accept-new diff --git a/icinga2/files/templates/byssh.conf b/icinga2/files/templates/byssh.conf new file mode 100644 index 0000000..4229b3f --- /dev/null +++ b/icinga2/files/templates/byssh.conf @@ -0,0 +1,12 @@ +template Service "byssh" { + import "generic-service" + vars.original_check_command = check_command + check_command = "by_ssh" + vars.by_ssh_port = 22 + vars.by_ssh_logname = "_icinga2" + vars.by_ssh_identity = "/var/icinga/.ssh/id_rsa" + + vars.by_ssh_command = {{ get_check_command(service.vars.original_check_command).command }} + vars.by_ssh_arguments = {{ get_check_command(service.vars.original_check_command).arguments }} + +} diff --git a/icinga2/files/templates/common.conf b/icinga2/files/templates/common.conf new file mode 100644 index 0000000..03da604 --- /dev/null +++ b/icinga2/files/templates/common.conf @@ -0,0 +1,7 @@ +template Host "common-host" { + import "generic-host" + + vars.notification["mail"] = { + groups = [ "icingaadmins" ] + } +} diff --git a/icinga2/files/templates/linux.conf b/icinga2/files/templates/linux.conf new file mode 100644 index 0000000..d84ca54 --- /dev/null +++ b/icinga2/files/templates/linux.conf @@ -0,0 +1,33 @@ +template Host "linux" { + import "common-host" + + vars.os = "Linux" + + vars.tcp_ipv4 += ["22"] + vars.load = { + load_percpu = true + load_wload1 = "0.9" + load_wload5 = "0.8" + load_wload15 = "0.7" + load_cload1 = "1.0" + load_cload5 = "0.9" + load_cload15 = "0.8" + } + + vars.procs["cron"] = { + procs_warning = "1:1" # warn range + procs_critical = "1:1" # crit range + procs_command = "cron" # command name (without path) + } + + vars.disks["/"] = { + disk_partition = "/" + disk_wfree = "20%" # warn free + disk_cfree = "10%" # crit free + } + + vars.swap = { + swap_wfree = "99%" + swap_cfree = "20%" + } +} diff --git a/icinga2/files/templates/openbsd.conf b/icinga2/files/templates/openbsd.conf new file mode 100644 index 0000000..7a7c5ed --- /dev/null +++ b/icinga2/files/templates/openbsd.conf @@ -0,0 +1,30 @@ +template Host "openbsd" { + import "common-host" + + vars.os = "OpenBSD" + + vars.tcp_ipv4 += ["22"] + vars.load = { + load_percpu = true + load_wload1 = "2.9" + load_wload5 = "2.8" + load_wload15 = "2.7" + load_cload1 = "3.0" + load_cload5 = "2.9" + load_cload15 = "2.8" + } + + + vars.disks["disk"] = { + disk_wfree = "20%" # warn free + disk_cfree = "10%" # crit free + } + + + vars.swap = { + swap_wfree = "99%" + swap_cfree = "20%" + } + + vars.maintenance_downtime = "01:00-04:00" +} diff --git a/icinga2/handlers/main.yml b/icinga2/handlers/main.yml new file mode 100644 index 0000000..9e042f1 --- /dev/null +++ b/icinga2/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: restart_icinga2 + become: yes + service: + name: icinga2 + state: restarted diff --git a/icinga2/tasks/main.yml b/icinga2/tasks/main.yml new file mode 100644 index 0000000..01fac15 --- /dev/null +++ b/icinga2/tasks/main.yml @@ -0,0 +1,53 @@ +--- +- name: ubuntu install + include: "ubuntu.yml" + when: ansible_distribution == 'Ubuntu' + vars: + ansible_become: yes +- name: openbsd install + include: "openbsd.yml" + when: ansible_distribution | lower == 'openbsd' + vars: + ansible_become: yes +- name: copy templates + become: yes + copy: + src: templates/ + dest: /etc/icinga2/conf.d/templates/ + notify: restart_icinga2 +- name: copy services + become: yes + copy: + src: services/ + dest: /etc/icinga2/conf.d/services/ + notify: restart_icinga2 +- name: copy commands + become: yes + copy: + src: commands/ + dest: /etc/icinga2/conf.d/commands/ + notify: restart_icinga2 +- name: copy notification config + become: yes + copy: + src: notifications.conf + dest: /etc/icinga2/conf.d/notifications.conf +- name: copy downtime config + become: yes + copy: + src: downtimes.conf + dest: /etc/icinga2/conf.d/downtimes.conf +- name: template user config + become: yes + template: + src: users.conf + dest: /etc/icinga2/conf.d/users.conf + notify: restart_icinga2 +- name: delete default hosts and services + become: yes + file: + path: "{{ item }}" + state: absent + loop: + - /etc/icinga2/conf.d/services.conf + - /etc/icinga2/conf.d/hosts.conf diff --git a/icinga2/tasks/openbsd.yml b/icinga2/tasks/openbsd.yml new file mode 100644 index 0000000..0ae064e --- /dev/null +++ b/icinga2/tasks/openbsd.yml @@ -0,0 +1,98 @@ +--- +- name: install prequisities + package: + name: "{{ item }}" + loop: "{{ icinga2_packages_pre_openbsd }}" + +- name: reload facts + setup: + +- name: install packages + package: + name: "{{ item }}" + loop: "{{ icinga2_packages }}" + +- name: enable and start rc service + service: + name: "{{ item }}" + state: started + enabled: yes + loop: "{{ icinga2_systemd_services }}" + +- name: create mysql db + mysql_db: + login_host: "{{ icinga2_mysql_auth.host }}" + login_user: "{{ icinga2_mysql_auth.user }}" + login_password: "{{ icinga2_mysql_auth.password }}" + name: "{{ icinga2_mysql_db.name }}" + state: present + target: "{{ icinga2_mysql_db.schema_openbsd }}" + register: db_created + +- name: import mysql schema + mysql_db: + login_host: "{{ icinga2_mysql_auth.host }}" + login_user: "{{ icinga2_mysql_auth.user }}" + login_password: "{{ icinga2_mysql_auth.password }}" + name: "{{ icinga2_mysql_db.name }}" + state: import + target: "{{ icinga2_mysql_db.schema_openbsd }}" + when: db_created.changed + +- name: create mysql users + mysql_user: + login_host: "{{ icinga2_mysql_auth.host }}" + login_user: "{{ icinga2_mysql_auth.user }}" + login_password: "{{ icinga2_mysql_auth.password }}" + name: "{{ icinga2_mysql_db.user }}" + password: "{{ icinga2_mysql_db.password }}" + priv: "{{ icinga2_mysql_db.name }}.*:ALL" + state: present + +- name: deploy icinga2 ido-mysql config + template: + src: ido-mysql.conf + dest: /etc/icinga2/features-available/ido-mysql.conf + +- name: enable icinga2 features + command: "icinga2 feature enable {{ item }}" + loop: "{{ icinga2_features }}" + notify: restart_icinga2 + +- name: setup icinga2 api + command: "icinga2 api setup" + when: '"api" in icinga2_features' + +- name: configure icinga2 api users + template: + src: api-users.conf + dest: /etc/icinga2/conf.d/api-users.conf + when: '"api" in icinga2_features' + notify: restart_icinga2 + +- name: create icinga dirs + file: + path: "{{ item }}" + state: directory + owner: _icinga + loop: + - /var/icinga + - /var/icinga/.ssh + +- name: create ssh key + openssh_keypair: + path: /var/icinga/.ssh/id_rsa + +- name: set ssh key owner + file: + path: "{{ item }}" + owner: _icinga + loop: + - /var/icinga/.ssh/id_rsa + - /var/icinga/.ssh/id_rsa.pub + +- name: copy ssh config + copy: + src: ssh_config + dest: /var/icinga/.ssh/config + owner: _icinga diff --git a/icinga2/tasks/ubuntu.yml b/icinga2/tasks/ubuntu.yml new file mode 100644 index 0000000..de95ab9 --- /dev/null +++ b/icinga2/tasks/ubuntu.yml @@ -0,0 +1,82 @@ +--- +- name: install prequisities + package: + name: "{{ item }}" + loop: "{{ icinga2_packages_pre }}" + +- name: reload facts + setup: + +- name: add icinga2 repo key + apt_key: + url: "{{ icinga2_repo.key.url }}" + state: present + ignore_errors: yes + +- name: add icinga2 repo + apt_repository: + repo: "{{ icinga2_repo.repo }}" + state: present + +- name: install packages + package: + name: "{{ item }}" + loop: "{{ icinga2_packages }}" + +- name: enable and start systemd service + systemd: + name: "{{ item }}" + state: started + enabled: yes + loop: "{{ icinga2_systemd_services }}" + +- name: create mysql db + mysql_db: + login_host: "{{ icinga2_mysql_auth.host }}" + login_user: "{{ icinga2_mysql_auth.user }}" + login_password: "{{ icinga2_mysql_auth.password }}" + name: "{{ icinga2_mysql_db.name }}" + state: present + target: "{{ icinga2_mysql_db.schema }}" + register: db_created + +- name: import mysql schema + mysql_db: + login_host: "{{ icinga2_mysql_auth.host }}" + login_user: "{{ icinga2_mysql_auth.user }}" + login_password: "{{ icinga2_mysql_auth.password }}" + name: "{{ icinga2_mysql_db.name }}" + state: import + target: "{{ icinga2_mysql_db.schema }}" + when: db_created.changed + +- name: create mysql users + mysql_user: + login_host: "{{ icinga2_mysql_auth.host }}" + login_user: "{{ icinga2_mysql_auth.user }}" + login_password: "{{ icinga2_mysql_auth.password }}" + name: "{{ icinga2_mysql_db.user }}" + password: "{{ icinga2_mysql_db.password }}" + priv: "{{ icinga2_mysql_db.name }}.*:ALL" + state: present + +- name: deploy icinga2 ido-mysql config + template: + src: ido-mysql.conf + dest: /etc/icinga2/features-available/ido-mysql.conf + +- name: enable icinga2 features + command: "icinga2 feature enable {{ item }}" + loop: "{{ icinga2_features }}" + notify: restart_icinga2 + +- name: setup icinga2 api + command: "icinga2 api setup" + when: '"api" in icinga2_features' + +- name: configure icinga2 api users + template: + src: api-users.conf + dest: /etc/icinga2/conf.d/api-users.conf + when: '"api" in icinga2_features' + notify: restart_icinga2 diff --git a/icinga2/templates/api-users.conf b/icinga2/templates/api-users.conf new file mode 100644 index 0000000..4819e64 --- /dev/null +++ b/icinga2/templates/api-users.conf @@ -0,0 +1,6 @@ +{% for user in icinga2_api_users %} +object ApiUser "{{ user.name }}" { + password = "{{ user.password }}" + permissions = {{ user.permissions }} +} +{% endfor %} diff --git a/icinga2/templates/ido-mysql.conf b/icinga2/templates/ido-mysql.conf new file mode 100644 index 0000000..802cafe --- /dev/null +++ b/icinga2/templates/ido-mysql.conf @@ -0,0 +1,6 @@ +object IdoMysqlConnection "ido-mysql" { + user = "{{ icinga2_mysql_db.user }}" + password = "{{ icinga2_mysql_db.password }}" + host = "{{ icinga2_mysql_auth.host }}" + database = "{{ icinga2_mysql_db.name }}" +} diff --git a/icinga2/templates/users.conf b/icinga2/templates/users.conf new file mode 100644 index 0000000..da69bac --- /dev/null +++ b/icinga2/templates/users.conf @@ -0,0 +1,13 @@ +object User "icingaadmin" { + import "generic-user" + + display_name = "Icinga 2 Admin" + groups = [ "icingaadmins" ] + + email = "{{ icinga2_admin_mail }}" +} + +object UserGroup "icingaadmins" { + display_name = "Icinga 2 Admin Group" +} + diff --git a/icinga2/vars/main.yml b/icinga2/vars/main.yml new file mode 100644 index 0000000..fe7f919 --- /dev/null +++ b/icinga2/vars/main.yml @@ -0,0 +1,22 @@ +icinga2_repo: + name: icinga2-repo + key: + url: "https://packages.icinga.com:443/icinga.key" + repo: "deb https://packages.icinga.com/ubuntu icinga-bionic main" + +icinga2_packages_pre: + - ca-certificates + - wget + - python3-mysqldb + +icinga2_packages_pre_openbsd: + - wget + - py3-pymysql + +icinga2_packages: + - icinga2 + - monitoring-plugins + - icinga2-ido-mysql + +icinga2_systemd_services: + - icinga2 diff --git a/icinga_director/defaults/main.yml b/icinga_director/defaults/main.yml new file mode 100644 index 0000000..6be357b --- /dev/null +++ b/icinga_director/defaults/main.yml @@ -0,0 +1,8 @@ +--- +director_mysql_auth: + host: "127.0.0.1" + user: "root" + password: "CHANGEME" + +director_password: CHANGEME + diff --git a/icinga_director/files/config.ini b/icinga_director/files/config.ini new file mode 100644 index 0000000..ef128e5 --- /dev/null +++ b/icinga_director/files/config.ini @@ -0,0 +1,2 @@ +[db] +resource = "director" diff --git a/icinga_director/files/icinga-director.service b/icinga_director/files/icinga-director.service new file mode 100644 index 0000000..f96f1d7 --- /dev/null +++ b/icinga_director/files/icinga-director.service @@ -0,0 +1,21 @@ +[Unit] +Description=Icinga Director - Monitoring Configuration +Documentation=https://icinga.com/docs/director/latest/ +Wants=network.target + +[Service] +EnvironmentFile=-/etc/default/icinga-director +EnvironmentFile=-/etc/sysconfig/icinga-director +ExecStart=/usr/bin/icingacli director daemon run +ExecReload=/bin/kill -HUP ${MAINPID} +User=icingadirector +SyslogIdentifier=icingadirector +Type=notify + +NotifyAccess=main +WatchdogSec=10 +RestartSec=30 +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/icinga_director/tasks/main.yml b/icinga_director/tasks/main.yml new file mode 100644 index 0000000..1cb1f01 --- /dev/null +++ b/icinga_director/tasks/main.yml @@ -0,0 +1,11 @@ +--- +- name: ubuntu install + include: "ubuntu.yml" + when: ansible_distribution == 'Ubuntu' + vars: + ansible_become: yes +- name: openbsd install + include: "openbsd.yml" + when: ansible_distribution | lower == 'openbsd' + vars: + ansible_become: yes diff --git a/icinga_director/tasks/openbsd.yml b/icinga_director/tasks/openbsd.yml new file mode 100644 index 0000000..e89981f --- /dev/null +++ b/icinga_director/tasks/openbsd.yml @@ -0,0 +1,84 @@ +--- +- name: Install dependencies + package: + name: "{{ item }}" + state: present + loop: "{{ director_packages_openbsd }}" + +- name: reload facts + setup: + +- name: Download modules from github + git: + repo: "https://github.com/Icinga/icingaweb2-module-{{ item.name }}.git" + dest: "{{ director_modules_dir_openbsd }}/{{ item.name }}" + update: no + version: "{{ item.version }}" + loop: "{{ director_modules }}" + ignore_errors: yes + tags: minimal + +- name: enable modules + shell: "icingacli module enable {{ item.name }}" + loop: "{{ director_modules }}" + tags: minimal + +- name: create mysql dbs + mysql_db: + login_host: "{{ director_mysql_auth.host }}" + login_user: "{{ director_mysql_auth.user }}" + login_password: "{{ director_mysql_auth.password }}" + name: "{{ item.name }}" + state: present + target: "{{ item.schema_openbsd }}" + loop: "{{ director_mysql_dbs }}" + register: dbs_created +- name: import mysql schema + mysql_db: + login_host: "{{ director_mysql_auth.host }}" + login_user: "{{ director_mysql_auth.user }}" + login_password: "{{ director_mysql_auth.password }}" + name: "{{ item.name }}" + state: import + target: "{{ item.schema_openbsd }}" + loop: "{{ director_mysql_dbs }}" + when: dbs_created.changed + +- name: create mysql users + mysql_user: + login_host: "{{ director_mysql_auth.host }}" + login_user: "{{ director_mysql_auth.user }}" + login_password: "{{ director_mysql_auth.password }}" + name: "{{ item.user }}" + password: "{{ item.password }}" + priv: "{{ item.name }}.*:ALL" + state: present + loop: "{{ director_mysql_dbs }}" + +- name: create icingaweb2 resource + ini_file: + path: /var/www/etc/icingaweb2/resources.ini + section: "{{ item.name }}" + option: "{{ item.option }}" + value: "{{ item.value }}" + loop: "{{ director_icingaweb_resources }}" + +- name: create icingadirector user + user: + name: "{{ director_user.name }}" + group: "{{ director_user.group }}" + home: "{{ director_user.home }}" + shell: "{{ director_user.shell }}" + create_home: yes + +- name: ensure icinga director config dir exists + file: + path: /var/www/etc/icingaweb2/modules/director + state: directory + +- name: copy icinga director config.ini + copy: + src: config.ini + dest: /var/www/etc/icingaweb2/modules/director/config.ini + owner: www-data + group: icingaweb2 diff --git a/icinga_director/tasks/ubuntu.yml b/icinga_director/tasks/ubuntu.yml new file mode 100644 index 0000000..1770bfd --- /dev/null +++ b/icinga_director/tasks/ubuntu.yml @@ -0,0 +1,98 @@ +--- +- name: Install dependencies + package: + name: "{{ item }}" + state: present + loop: "{{ director_packages }}" + +- name: reload facts + setup: + +- name: Download modules from github + git: + repo: "https://github.com/Icinga/icingaweb2-module-{{ item.name }}.git" + dest: "{{ director_modules_dir }}/{{ item.name }}" + update: no + version: "{{ item.version }}" + loop: "{{ director_modules }}" + ignore_errors: yes + tags: minimal + +- name: enable modules + shell: "icingacli module enable {{ item.name }}" + loop: "{{ director_modules }}" + tags: minimal + +- name: create mysql dbs + mysql_db: + login_host: "{{ director_mysql_auth.host }}" + login_user: "{{ director_mysql_auth.user }}" + login_password: "{{ director_mysql_auth.password }}" + name: "{{ item.name }}" + state: present + target: "{{ item.schema }}" + loop: "{{ director_mysql_dbs }}" + register: dbs_created +- name: import mysql schema + mysql_db: + login_host: "{{ director_mysql_auth.host }}" + login_user: "{{ director_mysql_auth.user }}" + login_password: "{{ director_mysql_auth.password }}" + name: "{{ item.name }}" + state: import + target: "{{ item.schema }}" + loop: "{{ director_mysql_dbs }}" + when: dbs_created.changed + +- name: create mysql users + mysql_user: + login_host: "{{ director_mysql_auth.host }}" + login_user: "{{ director_mysql_auth.user }}" + login_password: "{{ director_mysql_auth.password }}" + name: "{{ item.user }}" + password: "{{ item.password }}" + priv: "{{ item.name }}.*:ALL" + state: present + loop: "{{ director_mysql_dbs }}" + +- name: create icingaweb2 resource + ini_file: + path: /etc/icingaweb2/resources.ini + section: "{{ item.name }}" + option: "{{ item.option }}" + value: "{{ item.value }}" + loop: "{{ director_icingaweb_resources }}" + +- name: create icingadirector user + user: + name: "{{ director_user.name }}" + group: "{{ director_user.group }}" + home: "{{ director_user.home }}" + shell: "{{ director_user.shell }}" + create_home: yes + +- name: ensure icinga director config dir exists + file: + path: /etc/icingaweb2/modules/director + state: directory + +- name: copy icinga director config.ini + copy: + src: config.ini + dest: /etc/icingaweb2/modules/director/config.ini + owner: www-data + group: icingaweb2 + +- name: copy systemd unit file + copy: + src: icinga-director.service + dest: /etc/systemd/system/icinga-director.service + register: unitfile + +- name: reload systemd + systemd: + name: icinga-director + enabled: yes + state: started + daemon_reload: yes + when: unitfile.changed diff --git a/icinga_director/vars/main.yml b/icinga_director/vars/main.yml new file mode 100644 index 0000000..a2ae7db --- /dev/null +++ b/icinga_director/vars/main.yml @@ -0,0 +1,64 @@ +director_user: + name: icingadirector + group: icingaweb2 + home: /var/lib/icingadirector + shell: /bin/false + +director_modules_dir: "/usr/share/icingaweb2/modules" +director_modules_dir_openbsd: "/var/www/icinga-web2/modules" + +director_modules: + - name: reactbundle + version: v0.9.0 + - name: ipl + version: v0.5.0 + - name: incubator + version: v0.6.0 + - name: director + version: v1.8.0 + +director_packages: + - git + - python3-mysqldb + - php-curl + - php-posix + - php-sockets + +director_packages_openbsd: + - git + +director_mysql_dbs: + - name: director + user: director + password: "{{ director_password }}" + schema: "{{ director_modules_dir }}/director/schema/mysql.sql" + schema_openbsd: "{{ director_modules_dir_openbsd }}/director/schema/mysql.sql" + +director_icingaweb_resources: + - name: director + option: type + value: db + - name: director + option: db + value: mysql + - name: director + option: host + value: "127.0.0.1" + - name: director + option: port + value: "" + - name: director + option: dbname + value: director + - name: director + option: username + value: director + - name: director + option: password + value: "{{ director_password }}" + - name: director + option: charset + value: utf8 + - name: director + option: use_ssl + value: "0" diff --git a/icingaweb2-grafana/handlers/main.yml b/icingaweb2-grafana/handlers/main.yml new file mode 100644 index 0000000..df333bc --- /dev/null +++ b/icingaweb2-grafana/handlers/main.yml @@ -0,0 +1,5 @@ +- name: restart_grafana + become: yes + service: + name: grafana + state: restarted diff --git a/icingaweb2-grafana/tasks/main.yml b/icingaweb2-grafana/tasks/main.yml new file mode 100644 index 0000000..62a893c --- /dev/null +++ b/icingaweb2-grafana/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- name: ubuntu install + include: "ubuntu.yml" + when: ansible_distribution == 'Ubuntu' + vars: + ansible_become: yes + +- name: openbsd install + include: "openbsd.yml" + when: ansible_distribution | lower == 'openbsd' + vars: + ansible_become: yes diff --git a/icingaweb2-grafana/tasks/openbsd.yml b/icingaweb2-grafana/tasks/openbsd.yml new file mode 100644 index 0000000..4cd215f --- /dev/null +++ b/icingaweb2-grafana/tasks/openbsd.yml @@ -0,0 +1,47 @@ +--- +- name: install packages + package: + name: "{{ grafana_packages_openbsd }}" + +- name: enable and start services + service: + name: "{{ item }}" + state: started + enabled: yes + loop: "{{ grafana_openbsd_services }}" + +- name: Download and install grafana icingaweb2 module + git: + repo: "{{ grafana_icingaweb2_module.repo }}" + dest: "{{ grafana_icingaweb2_modules_dir_openbsd }}/{{ grafana_icingaweb2_module.name }}" + update: no + version: "{{ grafana_icingaweb2_module.version }}" + ignore_errors: yes + +- name: icinga2 influxdb config template + template: + src: influxdb.conf + dest: /etc/icinga2/features-available/influxdb.conf + +- name: enable modules + shell: "icingacli module enable {{ grafana_icingaweb2_module.name }}" + +- name: create influxdb + influxdb_database: + hostname: "{{ grafana_influxdb.bindaddr }}" + database_name: "{{ grafana_influxdb.database }}" + username: "{{ grafana_influxdb.username }}" + +- name: enable icinga2 influxdb feature + shell: "icinga2 feature enable influxdb" + +- name: configure grafana + ini_file: + path: "{{ grafana_config_file_openbsd }}" + section: "{{ item.section }}" + option: "{{ item.option }}" + value: "{{ item.value }}" + loop: "{{ grafana_config_values }}" + notify: restart_grafana + + diff --git a/icingaweb2-grafana/tasks/ubuntu.yml b/icingaweb2-grafana/tasks/ubuntu.yml new file mode 100644 index 0000000..fb54d63 --- /dev/null +++ b/icingaweb2-grafana/tasks/ubuntu.yml @@ -0,0 +1,60 @@ +--- +- name: add repo keys + apt_key: + url: "{{ item.key.url }}" + state: present + loop: "{{ grafana_repos }}" + +- name: add repos + apt_repository: + repo: "{{ item.repo }}" + state: present + loop: "{{ grafana_repos }}" + +- name: install packages + package: + name: "{{ item }}" + loop: "{{ grafana_packages }}" + +- name: enable and start systemd services + systemd: + name: "{{ item }}" + state: started + daemon_reload: yes + enabled: yes + loop: "{{ grafana_systemd_services }}" + +- name: Download and install grafana icingaweb2 module + git: + repo: "{{ grafana_icingaweb2_module.repo }}" + dest: "{{ grafana_icingaweb2_modules_dir }}/{{ grafana_icingaweb2_module.name }}" + update: no + version: "{{ grafana_icingaweb2_module.version }}" + ignore_errors: yes + +- name: icinga2 influxdb config template + template: + src: influxdb.conf + dest: /etc/icinga2/features-available/influxdb.conf + +- name: enable modules + shell: "icingacli module enable {{ grafana_icingaweb2_module.name }}" + +- name: create influxdb + influxdb_database: + hostname: "{{ grafana_influxdb.bindaddr }}" + database_name: "{{ grafana_influxdb.database }}" + username: "{{ grafana_influxdb.username }}" + +- name: enable icinga2 influxdb feature + shell: "icinga2 feature enable influxdb" + +- name: enable anonymous grafana auth + ini_file: + path: "{{ grafana_config_file }}" + section: "{{ item.section }}" + option: "{{ item.option }}" + value: "{{ item.value }}" + loop: "{{ grafana_config_values }}" + + diff --git a/icingaweb2-grafana/templates/influxdb.conf b/icingaweb2-grafana/templates/influxdb.conf new file mode 100644 index 0000000..f4c6650 --- /dev/null +++ b/icingaweb2-grafana/templates/influxdb.conf @@ -0,0 +1,25 @@ +/** + * The InfluxdbWriter type writes check result metrics and + * performance data to an InfluxDB HTTP API + */ + +object InfluxdbWriter "influxdb" { + host = "{{ grafana_influxdb.bindaddr }}" + port = "{{ grafana_influxdb.bindport }}" + database = "{{ grafana_influxdb.database }}" + flush_threshold = 1024 + flush_interval = 10s + host_template = { + measurement = "$host.check_command$" + tags = { + hostname = "$host.name$" + } + } + service_template = { + measurement = "$service.check_command$" + tags = { + hostname = "$host.name$" + service = "$service.name$" + } + } +} diff --git a/icingaweb2-grafana/vars/main.yml b/icingaweb2-grafana/vars/main.yml new file mode 100644 index 0000000..6ff71bc --- /dev/null +++ b/icingaweb2-grafana/vars/main.yml @@ -0,0 +1,80 @@ +grafana_icingaweb2_modules_dir: /usr/share/icingaweb2/modules +grafana_icingaweb2_modules_dir_openbsd: /var/www/icinga-web2/modules/ +grafana_icingaweb2_module: + repo: https://github.com/Mikesch-mp/icingaweb2-module-grafana + version: v1.3.6 + name: grafana + +grafana_packages: + - python3-apt + - python3-influxdb + - python3-requests + - grafana + - influxdb + +grafana_packages_openbsd: + - git + - influxdb + - py3-influxdb + - py3-requests + - grafana + +grafana_repos: + - name: grafana-repo + key: + url: https://packages.grafana.com/gpg.key + state: present + repo: "deb https://packages.grafana.com/oss/deb stable main" + - name: influxdb-repo + key: + url: https://repos.influxdata.com/influxdb.key + repo: "deb https://repos.influxdata.com/ubuntu bionic stable" + state: present + +grafana_systemd_services: + - influxdb + - grafana-server + +grafana_openbsd_services: + - influxdb + - grafana + +grafana_influxdb: + bindaddr: 127.0.0.1 + bindport: 8086 + database: icinga2 + username: icinga2 + +grafana_config_file: /etc/grafana/grafana.ini +grafana_config_file_openbsd: /etc/grafana/config.ini +grafana_config_values: + - section: server + option: http_addr + value: 127.0.0.1 + - section: server + option: http_port + value: 3000 + - section: server + option: root_url + value: "%(protocol)s://%(domain)s:%(http_port)s/grafana-dashboards/" + - section: server + option: serve_from_sub_path + value: true + - section: database + option: type + value: sqlite3 + - section: database + option: host + value: 127.0.0.1 + - section: database + option: name + value: grafana + - section: database + option: user + value: grafana + - section: database + option: password + value: "{{ lookup('password', '/dev/null length=32') }}" + - section: auth.anonymous + option: enabled + value: true diff --git a/icingaweb2-theme/defaults/main.yml b/icingaweb2-theme/defaults/main.yml new file mode 100644 index 0000000..6cf340d --- /dev/null +++ b/icingaweb2-theme/defaults/main.yml @@ -0,0 +1,6 @@ +--- +theme_modules_dir: "/usr/share/icingaweb2/modules" + +theme_modules: + - name: company + version: v1.0.0 diff --git a/icingaweb2-theme/files/icinga-director.service b/icingaweb2-theme/files/icinga-director.service new file mode 100644 index 0000000..f96f1d7 --- /dev/null +++ b/icingaweb2-theme/files/icinga-director.service @@ -0,0 +1,21 @@ +[Unit] +Description=Icinga Director - Monitoring Configuration +Documentation=https://icinga.com/docs/director/latest/ +Wants=network.target + +[Service] +EnvironmentFile=-/etc/default/icinga-director +EnvironmentFile=-/etc/sysconfig/icinga-director +ExecStart=/usr/bin/icingacli director daemon run +ExecReload=/bin/kill -HUP ${MAINPID} +User=icingadirector +SyslogIdentifier=icingadirector +Type=notify + +NotifyAccess=main +WatchdogSec=10 +RestartSec=30 +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/icingaweb2-theme/tasks/main.yml b/icingaweb2-theme/tasks/main.yml new file mode 100644 index 0000000..b273b78 --- /dev/null +++ b/icingaweb2-theme/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: ubuntu install + include: "ubuntu.yml" + when: ansible_distribution == 'Ubuntu' diff --git a/icingaweb2-theme/tasks/ubuntu.yml b/icingaweb2-theme/tasks/ubuntu.yml new file mode 100644 index 0000000..e6b5143 --- /dev/null +++ b/icingaweb2-theme/tasks/ubuntu.yml @@ -0,0 +1,15 @@ +--- +- name: Download theme modules from github + git: + repo: "https://github.com/Icinga/icingaweb2-theme-{{ item.name }}.git" + dest: "{{ theme_modules_dir }}/{{ item.name }}" + update: no + version: "{{ item.version }}" + loop: "{{ theme_modules }}" + ignore_errors: yes + tags: minimal + +- name: enable modules + shell: "icingacli module enable {{ item.name }}" + loop: "{{ theme_modules }}" + tags: minimal diff --git a/icingaweb2/defaults/main.yml b/icingaweb2/defaults/main.yml new file mode 100644 index 0000000..dccd811 --- /dev/null +++ b/icingaweb2/defaults/main.yml @@ -0,0 +1,34 @@ +icingaweb2_vhost: "{{ ansible_fqdn }}" +icingaweb2_mysql_auth: + host: 127.0.0.1 + user: root + password: CHANGEME + +icingaweb2_tls_cert: "{{ webserver_tls_certificate | default(false) }}" +icingaweb2_tls_key: "{{ webserver_tls_key | default(false) }}" + +icingaweb2_mysql_db: + name: icingaweb2 + user: icingaweb2 + password: CHANGEME + schema: /usr/share/icingaweb2/etc/schema/mysql.schema.sql + schema_openbsd: /var/www/icinga-web2/etc/schema/mysql.schema.sql + +icingaweb2_mysql_ido_db: + host: 127.0.0.1 + name: icinga2 + user: icinga2 + password: CHANGEME + +icingaweb2_modules: + - monitoring + +icingaweb2_web_user: + name: icingaadmin + password: CHANGEME + +icingaweb2_api_transport: + user: icingaweb2 + password: CHANGEME + host: localhost + port: 5665 diff --git a/icingaweb2/files/etc/icingaweb2/authentication.ini b/icingaweb2/files/etc/icingaweb2/authentication.ini new file mode 100644 index 0000000..a202cad --- /dev/null +++ b/icingaweb2/files/etc/icingaweb2/authentication.ini @@ -0,0 +1,3 @@ +[icingaweb2] +backend = "db" +resource = "icingaweb_db" diff --git a/icingaweb2/files/etc/icingaweb2/config.ini b/icingaweb2/files/etc/icingaweb2/config.ini new file mode 100644 index 0000000..70bf9e3 --- /dev/null +++ b/icingaweb2/files/etc/icingaweb2/config.ini @@ -0,0 +1,9 @@ +[global] +show_stacktraces = "1" +config_backend = "db" +config_resource = "icingaweb_db" + +[logging] +log = "file" +level = "ERROR" +file = "/var/log/icingaweb2/icingaweb2.log" diff --git a/icingaweb2/files/etc/icingaweb2/groups.ini b/icingaweb2/files/etc/icingaweb2/groups.ini new file mode 100644 index 0000000..6852ece --- /dev/null +++ b/icingaweb2/files/etc/icingaweb2/groups.ini @@ -0,0 +1,3 @@ +[icingaweb2] +backend = "db" +resource = "icingaweb_db" diff --git a/icingaweb2/files/etc/icingaweb2/modules/monitoring/backends.ini b/icingaweb2/files/etc/icingaweb2/modules/monitoring/backends.ini new file mode 100644 index 0000000..0dafae4 --- /dev/null +++ b/icingaweb2/files/etc/icingaweb2/modules/monitoring/backends.ini @@ -0,0 +1,3 @@ +[icinga2_ido_mysql] +type = "ido" +resource = "icinga_ido" diff --git a/icingaweb2/files/etc/icingaweb2/roles.ini b/icingaweb2/files/etc/icingaweb2/roles.ini new file mode 100644 index 0000000..39b0aa6 --- /dev/null +++ b/icingaweb2/files/etc/icingaweb2/roles.ini @@ -0,0 +1,5 @@ +[Administrators] +users = icingaadmin +permissions = "*" +groups = "Administrators" + diff --git a/icingaweb2/files/hosts b/icingaweb2/files/hosts new file mode 100644 index 0000000..9ddcc8c --- /dev/null +++ b/icingaweb2/files/hosts @@ -0,0 +1,2 @@ +127.0.0.1 localhost +::1 localhost diff --git a/icingaweb2/files/php-fpm.conf b/icingaweb2/files/php-fpm.conf new file mode 100644 index 0000000..631a81d --- /dev/null +++ b/icingaweb2/files/php-fpm.conf @@ -0,0 +1,15 @@ +[icingaweb2] +user = _icingaweb2 +group = icingaweb2 +listen = /var/www/run/php-fpm-icingaweb2.sock +listen.owner = www +listen.group = www +listen.mode = 0660 +pm = dynamic +pm.max_children = 20 +pm.start_servers = 4 +pm.min_spare_servers = 2 +pm.max_spare_servers = 5 +chroot = /var/www +env[TMP] = /icinga-web2/tmp +env[TMPDIR] = /icinga-web2/tmp diff --git a/icingaweb2/handlers/main.yml b/icingaweb2/handlers/main.yml new file mode 100644 index 0000000..d0654f4 --- /dev/null +++ b/icingaweb2/handlers/main.yml @@ -0,0 +1,17 @@ +- name: restart_relayd + become: yes + service: + name: relayd + state: restarted + +- name: restart_httpd + become: yes + service: + name: httpd + state: restarted + +- name: restart_php_fpm + become: yes + service: + name: php74_fpm + state: restarted diff --git a/icingaweb2/tasks/main.yml b/icingaweb2/tasks/main.yml new file mode 100644 index 0000000..1cb1f01 --- /dev/null +++ b/icingaweb2/tasks/main.yml @@ -0,0 +1,11 @@ +--- +- name: ubuntu install + include: "ubuntu.yml" + when: ansible_distribution == 'Ubuntu' + vars: + ansible_become: yes +- name: openbsd install + include: "openbsd.yml" + when: ansible_distribution | lower == 'openbsd' + vars: + ansible_become: yes diff --git a/icingaweb2/tasks/openbsd.yml b/icingaweb2/tasks/openbsd.yml new file mode 100644 index 0000000..b023b05 --- /dev/null +++ b/icingaweb2/tasks/openbsd.yml @@ -0,0 +1,173 @@ +--- +- name: install packages + openbsd_pkg: + name: "{{ icingaweb2_packages_openbsd }}" + +- name: add icingaweb2 group + group: + name: "{{ icingaweb2_group.name }}" + system: yes + state: present + +- name: ensure icingaweb2 user is in icingaweb2 group + user: + name: "{{ icingaweb2_user.name }}" + groups: "{{ icingaweb2_user.groups }}" + state: present + +- name: create icingaweb2 mysql db + mysql_db: + login_host: "{{ icingaweb2_mysql_auth.host }}" + login_user: "{{ icingaweb2_mysql_auth.user }}" + login_password: "{{ icingaweb2_mysql_auth.password }}" + name: "{{ icingaweb2_mysql_db.name }}" + state: present + target: "{{ icingaweb2_mysql_db.schema_openbsd }}" + register: db_created + +- name: import mysql schema + mysql_db: + login_host: "{{ icingaweb2_mysql_auth.host }}" + login_user: "{{ icingaweb2_mysql_auth.user }}" + login_password: "{{ icinga2_mysql_auth.password }}" + name: "{{ icingaweb2_mysql_db.name }}" + state: import + target: "{{ icingaweb2_mysql_db.schema_openbsd }}" + when: db_created.changed + +- name: create mysql users + mysql_user: + login_host: "{{ icingaweb2_mysql_auth.host }}" + login_user: "{{ icingaweb2_mysql_auth.user }}" + login_password: "{{ icingaweb2_mysql_auth.password }}" + name: "{{ icingaweb2_mysql_db.user }}" + password: "{{ icingaweb2_mysql_db.password }}" + priv: "{{ icingaweb2_mysql_db.name }}.*:ALL" + state: present + +- name: create config dir + file: + path: "{{ item }}" + state: directory + mode: '0755' + loop: + - /var/www/etc + - /var/www/etc/icingaweb2 + +- name: copy hosts file to httpd chroot + copy: + src: hosts + dest: /var/www/etc/hosts + +- name: deploy /etc/icingaweb2 skeleton files + copy: + src: etc/icingaweb2/ + dest: /var/www/etc/icingaweb2/ + +- name: configure icingaweb2 resources + template: + src: resources.ini + dest: /var/www/etc/icingaweb2/resources.ini + +- name: configure icingaweb2 command transport + template: + src: commandtransports.ini + dest: /var/www/etc/icingaweb2/modules/monitoring/commandtransports.ini + +- name: copy sql script for icingaweb2 user creation + template: + src: icingaweb-admin.sql + dest: /tmp/icingaweb-admin.sql + +- name: create icingaweb2 admin user + mysql_db: + login_host: "{{ icingaweb2_mysql_auth.host }}" + login_user: "{{ icingaweb2_mysql_auth.user }}" + login_password: "{{ icinga2_mysql_auth.password }}" + name: "{{ icingaweb2_mysql_db.name }}" + state: import + target: /tmp/icingaweb-admin.sql + ignore_errors: yes + +- name: enable icingaweb2 modules + command: "icingacli module enable {{ item }}" + loop: "{{ icingaweb2_modules }}" + +- name: write httpd config + template: + dest: /etc/httpd.conf.icingaweb2 + src: httpd.conf + notify: restart_httpd + +- name: write relayd config + template: + dest: /etc/relayd.conf + src: relayd.conf + notify: restart_relayd + +- name: copy php-fpm config + copy: + src: php-fpm.conf + dest: /etc/php-fpm.d/icingaweb2.conf + notify: restart_php_fpm + +- name: activate pdo_mysql in php.conf + lineinfile: + path: /etc/php-7.4.ini + regexp: '^.*extension.*=.*pdo_mysql.*$' + line: 'extension=pdo_mysql' + notify: restart_php_fpm + +- name: activate curl in php.conf + lineinfile: + path: /etc/php-7.4.ini + regexp: '^.*extension.*=.*curl.*$' + line: 'extension=curl' + notify: restart_php_fpm + +- name: set timezone in php.ini + lineinfile: + path: /etc/php-7.4.ini + regexp: '^.*date.timezone.*=.*$' + line: 'date.timezone = Europe/Berlin' + notify: restart_php_fpm + +- name: include icingaweb2 config in httpd.conf + lineinfile: + path: /etc/httpd.conf + regexp: '^include.*/etc/httpd.conf.icingaweb2.*$' + line: 'include "/etc/httpd.conf.icingaweb2"' + notify: restart_httpd + +- name: disable default config + lineinfile: + path: /etc/httpd.conf + regexp: '^include.*/etc/httpd.conf.default.*$' + state: absent + notify: restart_httpd + +- name: set permission on /etc/icingaweb2 + file: + path: /var/www/etc/icingaweb2 + state: directory + recurse: yes + owner: _icingaweb2 + group: icingaweb2 + +- name: enable and start httpd and php-fpm + service: + name: "{{ item }}" + state: started + enabled: yes + loop: + - php74_fpm + - httpd + +- name: ensure relayd and httpd are enabled and started + service: + name: "{{ item }}" + state: started + enabled: yes + loop: + - httpd + - relayd diff --git a/icingaweb2/tasks/ubuntu.yml b/icingaweb2/tasks/ubuntu.yml new file mode 100644 index 0000000..919c3b2 --- /dev/null +++ b/icingaweb2/tasks/ubuntu.yml @@ -0,0 +1,107 @@ +--- +- name: add icingaweb2 repo key + apt_key: + url: "{{ icingaweb2_repo.key.url }}" + state: present + ignore_errors: yes + +- name: add icingaweb2 repo + apt_repository: + repo: "{{ icingaweb2_repo.repo }}" + state: present + +- name: install packages + package: + name: "{{ item }}" + loop: "{{ icingaweb2_packages }}" + +- name: enable and start systemd service + systemd: + name: "{{ item }}" + state: started + enabled: yes + loop: "{{ icingaweb2_systemd_services }}" + +- name: add icingaweb2 group + group: + name: "{{ icingaweb2_group.name }}" + system: yes + state: present + +- name: ensure icingaweb2 user is in icingaweb2 group + user: + name: "{{ icingaweb2_user.name }}" + groups: "{{ icingaweb2_user.groups }}" + state: present + +- name: create icingaweb2 mysql db + mysql_db: + login_host: "{{ icingaweb2_mysql_auth.host }}" + login_user: "{{ icingaweb2_mysql_auth.user }}" + login_password: "{{ icingaweb2_mysql_auth.password }}" + name: "{{ icingaweb2_mysql_db.name }}" + state: present + target: "{{ icingaweb2_mysql_db.schema }}" + register: db_created + +- name: import mysql schema + mysql_db: + login_host: "{{ icingaweb2_mysql_auth.host }}" + login_user: "{{ icingaweb2_mysql_auth.user }}" + login_password: "{{ icinga2_mysql_auth.password }}" + name: "{{ icingaweb2_mysql_db.name }}" + state: import + target: "{{ icingaweb2_mysql_db.schema }}" + when: db_created.changed + +- name: create mysql users + mysql_user: + login_host: "{{ icingaweb2_mysql_auth.host }}" + login_user: "{{ icingaweb2_mysql_auth.user }}" + login_password: "{{ icingaweb2_mysql_auth.password }}" + name: "{{ icingaweb2_mysql_db.user }}" + password: "{{ icingaweb2_mysql_db.password }}" + priv: "{{ icingaweb2_mysql_db.name }}.*:ALL" + state: present + +- name: deploy /etc/icingaweb2 skeleton files + synchronize: + src: etc/icingaweb2/ + dest: /etc/icingaweb2/ + +- name: configure icingaweb2 resources + template: + src: resources.ini + dest: /etc/icingaweb2/resources.ini + +- name: configure icingaweb2 command transport + template: + src: commandtransports.ini + dest: /etc/icingaweb2/modules/monitoring/commandtransports.ini + +- name: copy sql script for icingaweb2 user creation + template: + src: icingaweb-admin.sql + dest: /tmp/icingaweb-admin.sql + +- name: create icingaweb2 admin user + mysql_db: + login_host: "{{ icingaweb2_mysql_auth.host }}" + login_user: "{{ icingaweb2_mysql_auth.user }}" + login_password: "{{ icinga2_mysql_auth.password }}" + name: "{{ icingaweb2_mysql_db.name }}" + state: import + target: /tmp/icingaweb-admin.sql + ignore_errors: yes + +- name: enable icingaweb2 modules + command: "icingacli module enable {{ item }}" + loop: "{{ icingaweb2_modules }}" + +- name: set permission on /etc/icingaweb2 + file: + path: /etc/icingaweb2 + state: directory + recurse: yes + owner: www-data + group: icingaweb2 diff --git a/icingaweb2/templates/commandtransports.ini b/icingaweb2/templates/commandtransports.ini new file mode 100644 index 0000000..20e0f5d --- /dev/null +++ b/icingaweb2/templates/commandtransports.ini @@ -0,0 +1,6 @@ +[api-backend] +transport = "api" +host = "{{ icingaweb2_api_transport.host }}" +port = "{{ icingaweb2_api_transport.port }}" +username = "{{ icingaweb2_api_transport.user }}" +password = "{{ icingaweb2_api_transport.password }}" diff --git a/icingaweb2/templates/httpd.conf b/icingaweb2/templates/httpd.conf new file mode 100644 index 0000000..808709c --- /dev/null +++ b/icingaweb2/templates/httpd.conf @@ -0,0 +1,29 @@ +server "{{ icingaweb2_vhost }}" { + listen on * port 80 + alias "localhost" + alias "127.0.0.1" + + root "/icinga-web2/public" + + block return 301 "https://$SERVER_NAME$DOCUMENT_URI" +} + +server "{{ icingaweb2_vhost }}" { + listen on 127.0.0.1 port 8080 + alias "localhost" + alias "127.0.0.1" + + root "/icinga-web2/public" + + directory index "index.php" + + location "*.php*" { + fastcgi socket "/run/php-fpm-icingaweb2.sock" + fastcgi param ICINGAWEB_CONFIGDIR "/etc/icingaweb2" + } + + + location not found "*" { + request rewrite "/index.php?$QUERY_STRING" + } +} diff --git a/icingaweb2/templates/icingaweb-admin.sql b/icingaweb2/templates/icingaweb-admin.sql new file mode 100644 index 0000000..c16f5e6 --- /dev/null +++ b/icingaweb2/templates/icingaweb-admin.sql @@ -0,0 +1,2 @@ +USE {{ icingaweb2_mysql_db.name }} +INSERT INTO icingaweb_user (name, active, password_hash) VALUES ('{{ icingaweb2_web_user.name }}', 1, '{{ icingaweb2_web_user.password | password_hash("md5") }}'); diff --git a/icingaweb2/templates/relayd.conf b/icingaweb2/templates/relayd.conf new file mode 100644 index 0000000..5cd5d7e --- /dev/null +++ b/icingaweb2/templates/relayd.conf @@ -0,0 +1,24 @@ +table { 127.0.0.1 } +table { 127.0.0.1 } + +http protocol https { + match request header append "X-Forwarded-For" value "$REMOTE_ADDR" + match request header append "X-Forwarded-By" \ + value "$SERVER_ADDR:$SERVER_PORT" + match request header set "Connection" value "close" + + match response header set "X-Frame-Options" value "SAMEORIGIN" + + pass request path "/grafana-dashboards/*" forward to + + tls keypair "{{ icingaweb2_vhost }}" + tcp { sack, backlog 128 } +} + +relay wwwtls { + listen on 0.0.0.0 port 443 tls + protocol https + + forward to port 8080 + forward to port 3000 +} diff --git a/icingaweb2/templates/resources.ini b/icingaweb2/templates/resources.ini new file mode 100644 index 0000000..66727d5 --- /dev/null +++ b/icingaweb2/templates/resources.ini @@ -0,0 +1,22 @@ +[icingaweb_db] +type = "db" +db = "mysql" +host = {{ icingaweb2_mysql_auth.host }} +port = 3306 +dbname = {{ icingaweb2_mysql_db.name }} +username = {{ icingaweb2_mysql_db.user }} +password = {{ icingaweb2_mysql_db.password }} +prefix = "icingaweb_" +charset = "utf8" +persistent = "0" + +[icinga_ido] +type = "db" +db = "mysql" +host = {{ icingaweb2_mysql_ido_db.host }} +port = 3306 +dbname = {{ icingaweb2_mysql_ido_db.name }} +username = {{ icingaweb2_mysql_ido_db.user }} +password = {{ icingaweb2_mysql_ido_db.password }} +charset = "utf8" +persistent = "0" diff --git a/icingaweb2/vars/main.yml b/icingaweb2/vars/main.yml new file mode 100644 index 0000000..4d79a3c --- /dev/null +++ b/icingaweb2/vars/main.yml @@ -0,0 +1,27 @@ +icingaweb2_repo: + name: icingaweb2-repo + key: + url: https://packages.icinga.com/icinga.key + repo: "deb https://packages.icinga.com/ubuntu icinga-bionic main" + +icingaweb2_packages_openbsd: + - rsync + - icinga-web2 + - php-curl%7.4 + +icingaweb2_packages: + - apache2 + - libapache2-mod-php + - icingaweb2 + - icingacli + +icingaweb2_systemd_services: + - apache2 + +icingaweb2_group: + name: icingaweb2 + +icingaweb2_user: + name: www-data + groups: + - icingaweb2 diff --git a/mailrelay/defaults/main.yml b/mailrelay/defaults/main.yml new file mode 100644 index 0000000..524cd5a --- /dev/null +++ b/mailrelay/defaults/main.yml @@ -0,0 +1,4 @@ +mailrelay_host: "mail.1wilson.org" +mailrelay_port: "587" +mailrelay_user: "system-mail" +mailrelay_password: "SomePassword" diff --git a/mailrelay/handlers/main.yml b/mailrelay/handlers/main.yml new file mode 100644 index 0000000..80c2428 --- /dev/null +++ b/mailrelay/handlers/main.yml @@ -0,0 +1,15 @@ +- name: smtpd_reload + become: yes + service: + name: smtpd + state: restarted + +- name: postmap + become: yes + shell: postmap /etc/postfix/secrets + +- name: postfix_reload + become: yes + service: + name: postfix + state: restarted diff --git a/mailrelay/tasks/main.yml b/mailrelay/tasks/main.yml new file mode 100644 index 0000000..9eff319 --- /dev/null +++ b/mailrelay/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- name: OpenBSD mailrelay setup + include_tasks: openbsd.yml + when: ansible_distribution|lower == 'openbsd' + vars: + ansible_become: yes + +- name: Ubuntu mailrelay setup + include_tasks: ubuntu.yml + when: ansible_distribution|lower == 'ubuntu' + vars: + ansible_become: yes diff --git a/mailrelay/tasks/openbsd.yml b/mailrelay/tasks/openbsd.yml new file mode 100644 index 0000000..cb02c55 --- /dev/null +++ b/mailrelay/tasks/openbsd.yml @@ -0,0 +1,17 @@ +- name: deploy mail relay secrets + template: + src: secrets + dest: /etc/mail/secrets + owner: root + group: _smtpd + mode: 0640 + notify: smtpd_reload + +- name: deploy mail relay config + template: + src: smtpd.conf + dest: /etc/mail/smtpd.conf + owner: root + group: _smtpd + mode: 0640 + notify: smtpd_reload diff --git a/mailrelay/tasks/ubuntu.yml b/mailrelay/tasks/ubuntu.yml new file mode 100644 index 0000000..b5db0db --- /dev/null +++ b/mailrelay/tasks/ubuntu.yml @@ -0,0 +1,30 @@ +- name: install libsasl2-modules + package: + name: libsasl2-modules + state: latest + +- name: deploy mail relay secrets + template: + src: postfix_secrets + dest: /etc/postfix/secrets + owner: root + group: root + mode: 0600 + notify: postmap + +- name: configure mailrelay + lineinfile: + dest: /etc/postfix/main.cf + state: present + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + loop: + - line: "relayhost = [{{ mailrelay_host }}]:{{ mailrelay_port }}" + regexp: '^(\s*)relayhost(\s*)=.*$' + - line: "smtp_sasl_auth_enable = yes" + regexp: '^(\s*)smtp_sasl_auth_enable(\s*)=.*$' + - line: "smtp_sasl_password_maps = hash:/etc/postfix/secrets" + regexp: '^(\s*)smtp_sasl_password_maps(\s*)=.*$' + - line: "smtp_sasl_security_options = noanonymous" + regexp: '^(\s*)smtp_sasl_security_options(\s*)=.*$' + notify: postfix_reload diff --git a/mailrelay/templates/postfix_secrets b/mailrelay/templates/postfix_secrets new file mode 100644 index 0000000..37c84ba --- /dev/null +++ b/mailrelay/templates/postfix_secrets @@ -0,0 +1 @@ +[{{ mailrelay_host }}]:{{ mailrelay_port }} {{ mailrelay_user }}:{{ mailrelay_password }} diff --git a/mailrelay/templates/secrets b/mailrelay/templates/secrets new file mode 100644 index 0000000..cd076c1 --- /dev/null +++ b/mailrelay/templates/secrets @@ -0,0 +1 @@ +system-mail {{ mailrelay_user }}:{{ mailrelay_password }} diff --git a/mailrelay/templates/smtpd.conf b/mailrelay/templates/smtpd.conf new file mode 100644 index 0000000..9431210 --- /dev/null +++ b/mailrelay/templates/smtpd.conf @@ -0,0 +1,13 @@ +# ansible managed file +# managed by role 'mail_relay' + +table aliases file:/etc/mail/aliases +table secrets file:/etc/mail/secrets + +listen on lo0 + +action "local_mail" mbox alias +action "outbound" relay host smtp+tls://system-mail@{{ mailrelay_host }}:{{ mailrelay_port }} auth + +match from local for local action "local_mail" +match from local for any action "outbound" diff --git a/mailserver/defaults/main.yml b/mailserver/defaults/main.yml new file mode 100644 index 0000000..ca28d12 --- /dev/null +++ b/mailserver/defaults/main.yml @@ -0,0 +1,19 @@ +mailserver_fqdn: "{{ ansible_fqdn }}" +mailserver_domain: "{{ ansible_domain }}" +mailserver_tls_cert: "/etc/ssl/{{ mailserver_fqdn }}.crt" +mailserver_tls_key: "/etc/ssl/private/{{ mailserver_fqdn }}.key" +mailserver_senderscore_block: "10" +mailserver_senderscore_junk: "70" +mailserver_dkim: + key: "/etc/mail/dkim/{{ mailserver_domain }}.key" + pub: "/etc/mail/dkim/{{ mailserver_domain }}.pub" + selector: 20200828 + size: 1024 +mailserver_users: + - name: some_user + password: some_password + state: present + shell: /usr/bin/false +mailserver_aliases: + - key: root + value: some_user diff --git a/mailserver/handlers/main.yml b/mailserver/handlers/main.yml new file mode 100644 index 0000000..4093463 --- /dev/null +++ b/mailserver/handlers/main.yml @@ -0,0 +1,4 @@ +--- +- name: mailserver_reload_aliases + become: yes + command: "{{ mailserver_aliases_reload_command[ ansible_distribution|lower ] }}" diff --git a/mailserver/tasks/common.yml b/mailserver/tasks/common.yml new file mode 100644 index 0000000..92878c2 --- /dev/null +++ b/mailserver/tasks/common.yml @@ -0,0 +1,121 @@ +--- +- name: "install package: {{ package }}" + package: + name: "{{ package }}" + state: latest + loop: "{{ mailserver_packages[ ansible_distribution|lower ] }}" + loop_control: + loop_var: package + when: ansible_distribution|lower != 'openbsd' + +- name: "install package: {{ package }}" + community.general.openbsd_pkg: + name: "{{ package }}" + state: latest + snapshot: "{{ force_openbsd_snapshot|default(false) }}" + loop: "{{ mailserver_packages[ ansible_distribution|lower ] }}" + loop_control: + loop_var: package + when: ansible_distribution|lower == 'openbsd' + +- name: "create directory: {{ directory }}" + file: + path: "{{ directory.path }}" + state: directory + mode: "{{ directory.mode }}" + loop: "{{ mailserver_directories[ ansible_distribution|lower ] }}" + loop_control: + loop_var: directory + +- name: "template {{ cfg.path }}" + template: + src: "{{ cfg.template }}" + dest: "{{ cfg.path }}" + loop: "{{ mailserver_config_templates[ ansible_distribution|lower ] }}" + loop_control: + loop_var: cfg + +- name: "ensure {{ cfg.line }} is in {{ cfg.path }}" + lineinfile: + path: "{{ cfg.path }}" + line: "{{ cfg.line }}" + regexp: "{{ cfg.regexp }}" + loop: "{{ mailserver_config_insertions[ ansible_distribution|lower ] }}" + loop_control: + loop_var: cfg + register: mailserver_config_task + +- name: "setup mail users" + user: + name: "{{ user.name }}" + password: "{{ user.password }}" + state: "{{ user.state }}" + shell: "{{ user.shell }}" + update_password: always + loop: "{{ mailserver_users }}" + loop_control: + loop_var: user + tags: + - mailserver_users + +- name: "ensure aliases are present" + lineinfile: + path: "{{ mailserver_aliases_file_path[ ansible_distribution|lower ] }}" + line: "{{ alias.key }}: {{ alias.value }}" + regexp: '^(\s*){{ alias.key }}(\s*):.*$' + state: "{{ alias.state | default('present') }}" + loop: "{{ mailserver_aliases }}" + loop_control: + loop_var: alias + notify: mailserver_reload_aliases + tags: + - mailserver_aliases + +- name: "generate dkim private key" + openssl_privatekey: + path: "{{ mailserver_dkim.key }}" + size: "{{ mailserver_dkim.size }}" + +- name: "generate dkim public key" + openssl_publickey: + path: "{{ mailserver_dkim.pub }}" + privatekey_path: "{{ mailserver_dkim.key }}" + mode: "0640" + group: "_rspamd" + register: dkim_pubkey_task + +- name: "Use slurp module to get dkim public key" + slurp: + src: "{{ mailserver_dkim.pub }}" + register: dkim_pubkey_base64 + +- name: "Ensure ansible local facts dir exists" + file: + path: /etc/ansible/facts.d + state: directory + +- name: "Persist dkim pubkey as local fact." + copy: + content: "{ 'dkim_pub_key' : \"{{ (dkim_pubkey_base64['content']|b64decode|replace('\n', ''))[26:-24] }}\" }" + dest: /etc/ansible/facts.d/mailserver.fact + owner: "{{ ansible_ssh_user }}" + mode: "0644" + +- name: "start and enable: {{ service }}" + service: + name: "{{ service }}" + enabled: True + state: started + loop: "{{ mailserver_services[ ansible_distribution|lower ] }}" + loop_control: + loop_var: service + +- name: "restart: {{ service }}" + service: + name: "{{ service }}" + enabled: True + state: restarted + when: dkim_pubkey_task.changed or mailserver_config_task.changed + loop: "{{ mailserver_services[ ansible_distribution|lower ] }}" + loop_control: + loop_var: service diff --git a/mailserver/tasks/main.yml b/mailserver/tasks/main.yml new file mode 100644 index 0000000..8a57d04 --- /dev/null +++ b/mailserver/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- name: run common tasks + include_tasks: common.yml + vars: + ansible_become: yes + diff --git a/mailserver/templates/dkim_signing.conf.j2 b/mailserver/templates/dkim_signing.conf.j2 new file mode 100644 index 0000000..0fe0386 --- /dev/null +++ b/mailserver/templates/dkim_signing.conf.j2 @@ -0,0 +1,8 @@ +allow_username_mismatch = true; + +domain { + {{ mailserver_domain }} { + path = "{{ mailserver_dkim.key }}"; + selector = "{{ mailserver_dkim.selector }}"; + } +} diff --git a/mailserver/templates/smtpd.conf.j2 b/mailserver/templates/smtpd.conf.j2 new file mode 100644 index 0000000..ce4c735 --- /dev/null +++ b/mailserver/templates/smtpd.conf.j2 @@ -0,0 +1,32 @@ +pki {{ mailserver_fqdn }} cert "{{ mailserver_tls_cert }}" +pki {{ mailserver_fqdn }} key "{{ mailserver_tls_key }}" + +filter check_dyndns phase connect match rdns regex { '.*\.dyn\..*', '.*\.dsl\..*' } \ + disconnect "550 no residential connections" + +filter check_rdns phase connect match !rdns \ + disconnect "550 no rDNS is so 80s" + +filter check_fcrdns phase connect match !fcrdns \ + disconnect "550 no FCrDNS is so 80s" + +filter senderscore \ + proc-exec "filter-senderscore -blockBelow {{ mailserver_senderscore_block }} -junkBelow {{ mailserver_senderscore_junk }} -slowFactor 5000" + +filter rspamd proc-exec "filter-rspamd" + +table aliases file:/etc/mail/aliases + +listen on all tls pki {{ mailserver_fqdn }} \ + filter { check_dyndns, check_rdns, check_fcrdns, senderscore, rspamd } + +listen on all port submission tls-require pki {{ mailserver_fqdn }} auth filter rspamd + +action "local_mail" maildir junk alias +action "outbound" relay helo {{ mailserver_fqdn }} + +match from any for domain "{{ mailserver_domain }}" action "local_mail" +match for local action "local_mail" + +match from any auth for any action "outbound" +match for any action "outbound" diff --git a/mailserver/vars/main.yml b/mailserver/vars/main.yml new file mode 100644 index 0000000..f6484d0 --- /dev/null +++ b/mailserver/vars/main.yml @@ -0,0 +1,51 @@ +mailserver_aliases_file_path: + openbsd: /etc/mail/aliases + +mailserver_aliases_reload_command: + openbsd: smtpctl update table aliases + +mailserver_directories: + openbsd: + - path: /etc/rspamd/local.d + mode: '0755' + - path: /etc/mail/dkim + mode: '0750' + group: _rspamd + +mailserver_packages: + openbsd: + - py3-cryptography + - redis + - rspamd + - opensmtpd-filter-rspamd + - opensmtpd-filter-senderscore + - dovecot + +mailserver_services: + openbsd: + - redis + - rspamd + - smtpd + - dovecot + +mailserver_config_templates: + openbsd: + - path: /etc/rspamd/local.d/dkim_signing.conf + template: dkim_signing.conf.j2 + - path: /etc/mail/smtpd.conf + template: smtpd.conf.j2 + +mailserver_config_insertions: + openbsd: + - path: /etc/login.conf + line: "dovecot::openfiles-cur=1024::openfiles-max=2048::tc=daemon:" + regexp: '^(\s*)dovecot:.*$' + - path: /etc/dovecot/conf.d/10-ssl.conf + line: "ssl_cert = <{{ mailserver_tls_cert }}" + regexp: '^(\s*)ssl_cert(\s*)=.*$' + - path: /etc/dovecot/conf.d/10-ssl.conf + line: "ssl_key = <{{ mailserver_tls_key }}" + regexp: '^(\s*)ssl_key(\s*)=.*$' + - path: /etc/dovecot/conf.d/10-mail.conf + line: "mail_location = maildir:~/Maildir" + regexp: '^(\s*)mail_location(\s*)=.*$' diff --git a/mysql/defaults/main.yml b/mysql/defaults/main.yml new file mode 100644 index 0000000..b0a856f --- /dev/null +++ b/mysql/defaults/main.yml @@ -0,0 +1 @@ +mysql_root_password: CHANGEME diff --git a/mysql/tasks/main.yml b/mysql/tasks/main.yml new file mode 100644 index 0000000..1cb1f01 --- /dev/null +++ b/mysql/tasks/main.yml @@ -0,0 +1,11 @@ +--- +- name: ubuntu install + include: "ubuntu.yml" + when: ansible_distribution == 'Ubuntu' + vars: + ansible_become: yes +- name: openbsd install + include: "openbsd.yml" + when: ansible_distribution | lower == 'openbsd' + vars: + ansible_become: yes diff --git a/mysql/tasks/openbsd.yml b/mysql/tasks/openbsd.yml new file mode 100644 index 0000000..7fd07b4 --- /dev/null +++ b/mysql/tasks/openbsd.yml @@ -0,0 +1,38 @@ +--- +- name: install packages + package: + name: "{{ mysql_packages_openbsd }}" + +- name: check if database already exists + stat: + path: /var/mysql + register: db_exists + +- name: initialize database + command: /usr/local/bin/mysql_install_db + when: not db_exists.stat.exists + +- name: reload facts + setup: + +- name: enable and start mysqld + service: + name: mysqld + state: started + enabled: yes + +- name: change mysql root password + mysql_user: + name: root + login_unix_socket: /var/run/mysql/mysql.sock + host: "{{ item }}" + password: "{{ mysql_root_password }}" + login_user: root + login_password: "{{ mysql_root_password }}" + check_implicit_admin: yes + priv: "*.*:ALL,GRANT" + loop: + - "{{ ansible_hostname }}" + - 127.0.0.1 + - ::1 + - localhost diff --git a/mysql/tasks/ubuntu.yml b/mysql/tasks/ubuntu.yml new file mode 100644 index 0000000..fb91b7b --- /dev/null +++ b/mysql/tasks/ubuntu.yml @@ -0,0 +1,30 @@ +--- +- name: install packages + package: + name: "{{ item }}" + loop: "{{ mysql_packages }}" + +- name: reload facts + setup: + +- name: enable and start systemd service + systemd: + name: "{{ item }}" + state: started + enabled: yes + loop: "{{ mysql_systemd_services }}" + +- name: change mysql root password + mysql_user: + name: root + host: "{{ item }}" + password: "{{ mysql_root_password }}" + login_user: root + login_password: "{{ mysql_root_password }}" + check_implicit_admin: yes + priv: "*.*:ALL,GRANT" + loop: + - "{{ ansible_hostname }}" + - 127.0.0.1 + - ::1 + - localhost diff --git a/mysql/vars/main.yml b/mysql/vars/main.yml new file mode 100644 index 0000000..28f5c77 --- /dev/null +++ b/mysql/vars/main.yml @@ -0,0 +1,11 @@ +mysql_packages_openbsd: + - py3-pymysql + - mariadb-server + - mariadb-client +mysql_packages: + - python3-mysqldb + - mysql-server + - mysql-client +mysql_systemd_services: + - mysql + diff --git a/needs_refactoring/bootstrap/files/doas.conf b/needs_refactoring/bootstrap/files/doas.conf new file mode 100644 index 0000000..4d32f57 --- /dev/null +++ b/needs_refactoring/bootstrap/files/doas.conf @@ -0,0 +1,14 @@ +# $OpenBSD: doas.conf,v 1.1 2016/09/03 11:58:32 pirofti Exp $ +# Configuration sample file for doas(1). +# See doas.conf(5) for syntax and examples. + +# Non-exhaustive list of variables needed to build release(8) and ports(7) +#permit nopass setenv { \ +# FTPMODE PKG_CACHE PKG_PATH SM_PATH SSH_AUTH_SOCK \ +# DESTDIR DISTDIR FETCH_CMD FLAVOR GROUP MAKE MAKECONF \ +# MULTI_PACKAGES NOMAN OKAY_FILES OWNER PKG_DBDIR \ +# PKG_DESTDIR PKG_TMPDIR PORTSDIR RELEASEDIR SHARED_ONLY \ +# SUBPACKAGE WRKOBJDIR SUDO_PORT_V1 } :wsrc + +# Allow wheel by default +permit nopass keepenv :wheel diff --git a/needs_refactoring/bootstrap/files/id_rsa.pub b/needs_refactoring/bootstrap/files/id_rsa.pub new file mode 100644 index 0000000..2e06254 --- /dev/null +++ b/needs_refactoring/bootstrap/files/id_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCgZhoD7oDAVD9Rlq/lA+dfVaTtwjtPBjdIs0wr+LggONpbmUpgCNbRaYErMbM3+IQ9obFr4GK5nNQmw7Onwfxuup2JIXJFDuwXP7TsH12ZKpIVls4bc4yBOYizg+5PMs9yklKjMctgeizP6CDCdBOI5UdT6IuuS8T7z1yRzVV8+lGzGtaMgIqechtaTsDkYmLSC4dlIzuvyZeT/d9GKjtJpcmr/VgNFBO4jMr4vWCTC/pUt8Mgmal5hXFfEnL/itvp6b3VsDXT7aJjqFOSdqR5H11M6f7w+1t/GID7jEbMX3iqgmkr8ouYMiJxAMoDbVKZbL/2bbCBzz7FpY2xHDLL _ansible@mw-macbook.office.ciphron.de diff --git a/needs_refactoring/bootstrap/handlers/main.yml b/needs_refactoring/bootstrap/handlers/main.yml new file mode 100644 index 0000000..898aaa1 --- /dev/null +++ b/needs_refactoring/bootstrap/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: restart_sshd + service: + name: sshd + state: restarted diff --git a/needs_refactoring/bootstrap/tasks/arch.yml b/needs_refactoring/bootstrap/tasks/arch.yml new file mode 100644 index 0000000..a856fc6 --- /dev/null +++ b/needs_refactoring/bootstrap/tasks/arch.yml @@ -0,0 +1,11 @@ +--- +- name: ansible user + user: + name: "{{ service_account }}" + groups: wheel +- name: edit /etc/sudoers + lineinfile: + path: /etc/sudoers + regexp: "^%wheel" + line: "%wheel ALL=(ALL) NOPASSWD: ALL" + state: present diff --git a/needs_refactoring/bootstrap/tasks/common.yml b/needs_refactoring/bootstrap/tasks/common.yml new file mode 100644 index 0000000..17216ed --- /dev/null +++ b/needs_refactoring/bootstrap/tasks/common.yml @@ -0,0 +1,45 @@ +--- +- name: deploy ansible ssh key + authorized_key: + user: "{{ service_account }}" + state: present + key: "{{ lookup('file', ansible_ssh_public_key_file) }}" + register: add_identity_key + +- name: disable empty password ssh logins + lineinfile: dest={{ sshd_config }} + regexp="^PermitEmptyPasswords" + line="PermitEmptyPasswords no" + state=present + notify: restart_sshd +- name: disable empty password ssh logins + lineinfile: dest={{ sshd_config }} + regexp="^PermitEmptyPasswords (?!no)" + state=absent + notify: restart_sshd +- name: disable password ssh logins + lineinfile: dest={{ sshd_config }} + regexp="^PasswordAuthentication" + line="PasswordAuthentication no" + state=present + when: add_identity_key is success + notify: restart_sshd +- name: disable password ssh logins + lineinfile: dest={{ sshd_config }} + regexp="^PasswordAuthentication (?!no)" + state=absent + when: add_identity_key is success + notify: restart_sshd +- name: disable ssh root login + lineinfile: dest={{ sshd_config }} + regexp="^PermitRootLogin" + line="PermitRootLogin no" + state=present + when: add_identity_key is success + notify: restart_sshd +- name: disable ssh root login + lineinfile: dest={{ sshd_config }} + regexp="^PermitRootLogin (?!no)" + state=absent + when: add_identity_key is success + notify: restart_sshd diff --git a/needs_refactoring/bootstrap/tasks/main.yml b/needs_refactoring/bootstrap/tasks/main.yml new file mode 100644 index 0000000..f97ccc6 --- /dev/null +++ b/needs_refactoring/bootstrap/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- name: OpenBSD ansible bootstrap + import_tasks: openbsd.yml + when: ansible_distribution|lower == 'openbsd' +- name: ubuntu ansible bootstrap + import_tasks: ubuntu.yml + when: ansible_distribution|lower == 'ubuntu' +- name: arch linux ansible bootstrap + import_tasks: arch.yml + when: ansible_distribution|lower == 'archlinux' +- name: Common ansible bootstrap + import_tasks: common.yml diff --git a/needs_refactoring/bootstrap/tasks/openbsd.yml b/needs_refactoring/bootstrap/tasks/openbsd.yml new file mode 100644 index 0000000..39c3aa2 --- /dev/null +++ b/needs_refactoring/bootstrap/tasks/openbsd.yml @@ -0,0 +1,12 @@ +--- +- name: ansible user + user: + name: "{{ service_account }}" + groups: wheel +- name: /etc/doas.conf + copy: + src: doas.conf + dest: /etc/doas.conf + owner: root + group: wheel + mode: 0600 diff --git a/needs_refactoring/bootstrap/tasks/ubuntu.yml b/needs_refactoring/bootstrap/tasks/ubuntu.yml new file mode 100644 index 0000000..9ef8b8e --- /dev/null +++ b/needs_refactoring/bootstrap/tasks/ubuntu.yml @@ -0,0 +1,11 @@ +--- +- name: ansible user + user: + name: "{{ service_account }}" + groups: sudo +- name: edit /etc/sudoers + lineinfile: + path: /etc/sudoers + regexp: "^%sudo" + line: "%sudo ALL=(ALL) NOPASSWD: ALL" + state: present diff --git a/needs_refactoring/bootstrap/vars/main.yml b/needs_refactoring/bootstrap/vars/main.yml new file mode 100644 index 0000000..f766175 --- /dev/null +++ b/needs_refactoring/bootstrap/vars/main.yml @@ -0,0 +1,4 @@ +--- +sshd_config: /etc/ssh/sshd_config +service_account: _ansible +ansible_ssh_public_key_file: id_rsa.pub diff --git a/needs_refactoring/dhcpd/handlers/main.yml b/needs_refactoring/dhcpd/handlers/main.yml new file mode 100644 index 0000000..59d8847 --- /dev/null +++ b/needs_refactoring/dhcpd/handlers/main.yml @@ -0,0 +1,13 @@ +--- +- name: restart dhcpd + service: + name: dhcpd + state: restarted +- name: update dhcpd.conf + template: + src: dhcpd.conf + dest: /etc/dhcpd.conf + owner: root + group: wheel + mode: 640 + notify: restart dhcpd diff --git a/needs_refactoring/dhcpd/tasks/main.yml b/needs_refactoring/dhcpd/tasks/main.yml new file mode 100644 index 0000000..a2268f8 --- /dev/null +++ b/needs_refactoring/dhcpd/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: OpenBSD dhcpd + import_tasks: openbsd.yml + when: ansible_distribution|lower == 'openbsd' diff --git a/needs_refactoring/dhcpd/tasks/openbsd.yml b/needs_refactoring/dhcpd/tasks/openbsd.yml new file mode 100644 index 0000000..c195080 --- /dev/null +++ b/needs_refactoring/dhcpd/tasks/openbsd.yml @@ -0,0 +1,30 @@ +--- +- name: dhcpd.conf + template: + src: dhcpd.conf + dest: /etc/dhcpd.conf + owner: root + group: wheel + mode: 0644 + notify: restart dhcpd +- name: ensure dhcpd is enabled and started + service: + name: dhcpd + state: started +- name: define dhcpd_flags variable + set_fact: + dhcpd_flags: "{{ dhcpd_nets | map(attribute='interface') | join(' ')}}" +- name: dhcpd flags + lineinfile: + dest: /etc/rc.conf.local + regexp: "^dhcpd_flags=" + line: "dhcpd_flags=\"{{ dhcpd_flags }}\"" + create: yes + notify: restart dhcpd +- name: pf rules + lineinfile: + path: /etc/anchors/ansible + line: "pass in on {{ item.interface }} inet proto udp to port { 67 68 }" + with_items: + - "{{ dhcpd_nets }}" + notify: reload pf diff --git a/needs_refactoring/dhcpd/templates/dhcpd.conf b/needs_refactoring/dhcpd/templates/dhcpd.conf new file mode 100644 index 0000000..dc54945 --- /dev/null +++ b/needs_refactoring/dhcpd/templates/dhcpd.conf @@ -0,0 +1,19 @@ +option domain-name "{{ ansible_domain }}"; + +{% for net in dhcpd_nets %} +subnet {{ net.subnet }} netmask {{ net.netmask }} { + option routers {{ net.router }}; + option domain-name-servers {{ net.dns }}; + + range {{ net.range }}; + + {% for lease in static | default([]) %} + {% if lease.network == net.name %} + host {{ lease.host }} { + hardware ethernet {{ lease.lladdr }}; + fixed-address {{ lease.ip }}; + } + {% endif %} +{% endfor %} +} +{% endfor %} diff --git a/needs_refactoring/dns/handlers/main.yml b/needs_refactoring/dns/handlers/main.yml new file mode 100644 index 0000000..76eec02 --- /dev/null +++ b/needs_refactoring/dns/handlers/main.yml @@ -0,0 +1,15 @@ +- name: reload nsd + service: + name: nsd + state: reloaded + enabled: true +- name: reload unbound + service: + name: nsd + state: reloaded + enabled: true +- name: reload zonefiles + command: nsd-control reload + notify: notify slaves +- name: notify slaves + command: nsd-control notify diff --git a/needs_refactoring/dns/tasks/main.yml b/needs_refactoring/dns/tasks/main.yml new file mode 100644 index 0000000..ec62fb0 --- /dev/null +++ b/needs_refactoring/dns/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: OpenBSD dns + import_tasks: openbsd.yml + when: ansible_distribution|lower == 'openbsd' diff --git a/needs_refactoring/dns/tasks/openbsd.yml b/needs_refactoring/dns/tasks/openbsd.yml new file mode 100644 index 0000000..c0684ec --- /dev/null +++ b/needs_refactoring/dns/tasks/openbsd.yml @@ -0,0 +1,46 @@ +--- +- name: unbound.conf + template: + src: unbound.conf + dest: /var/unbound/etc/unbound.conf + owner: root + group: wheel + mode: 0644 + notify: reload unbound +- name: nsd.conf + template: + src: nsd.conf + dest: /var/nsd/etc/nsd.conf + owner: root + group: _nsd + mode: 0640 + notify: reload nsd +- name: forward zonefile(s) + template: + src: zonefile.forward + dest: "/var/nsd/zones/{{ item.role }}/{{ item.name }}" + owner: root + group: _nsd + mode: 0640 + with_items: + - "{{ dns_zones }}" + notify: reload zonefiles +- name: pf rules + lineinfile: + path: /etc/anchors/ansible + line: "{{ item }}" + notify: reload pf + with_items: + - "pass in inet proto udp to port 53" + - "pass out inet proto udp from port 53" + - "pass in on internal inet proto udp to port 53 rdr-to 127.0.0.1 port 5353" +- name: nsd started and enabled + service: + name: nsd + state: started + enabled: true +- name: unbound started and enabled + service: + name: unbound + state: started + enabled: true diff --git a/needs_refactoring/dns/templates/nsd.conf b/needs_refactoring/dns/templates/nsd.conf new file mode 100644 index 0000000..86b5c05 --- /dev/null +++ b/needs_refactoring/dns/templates/nsd.conf @@ -0,0 +1,39 @@ +# $OpenBSD: nsd.conf,v 1.13 2018/08/16 17:59:12 florian Exp $ + +server: + hide-version: yes + verbosity: 1 + database: "" # disable database + +remote-control: + control-enable: yes + control-interface: /var/run/nsd.sock + +## tsig key example +#key: +# name: "tsig1.example.com." +# algorithm: hmac-sha256 +# secret: "bWVrbWl0YXNkaWdvYXQ=" + +{% for zone in dns_zones %} +zone: + name: "{{ zone.name }}" + zonefile: "{{ zone.role }}/{{ zone.name }}" +{% if zone.role == "master" %} +{% for slave in zone.slaves %} + notify: {{ slave }} NOKEY + provide-xfr: {{ slave }} NOKEY +{% endfor %} +{% elif zone.role == "slave" %} +# allow-notify: 192.0.2.2 tsig1.example.com. +# request-xfr: 192.0.2.2 tsig1.example.com. +{% endif %} +{% endfor %} + +## slave zone example +#zone: +# name: "example.net" +# zonefile: "slave/example.net" +# allow-notify: 192.0.2.2 tsig1.example.com. +# request-xfr: 192.0.2.2 tsig1.example.com. + diff --git a/needs_refactoring/dns/templates/unbound.conf b/needs_refactoring/dns/templates/unbound.conf new file mode 100644 index 0000000..6b8e4a8 --- /dev/null +++ b/needs_refactoring/dns/templates/unbound.conf @@ -0,0 +1,46 @@ +# $OpenBSD: unbound.conf,v 1.8 2018/03/29 20:40:22 florian Exp $ + +server: + interface: 127.0.0.1@5353 # listen on alternative port + interface: ::1@5353 + + access-control: 0.0.0.0/0 allow + access-control: 127.0.0.0/8 allow + access-control: ::0/0 refuse + access-control: ::1 allow + + hide-identity: yes + hide-version: yes + + auto-trust-anchor-file: "/var/unbound/db/root.key" +{% for zone in dns_zones %} + domain-insecure: "{{ zone.name }}" +{% endfor %} + +remote-control: + control-enable: yes + control-use-cert: no + control-interface: /var/run/unbound.sock + + +{% for zone in dns_zones %} +stub-zone: + name: "{{ zone.name }}" + stub-addr: "{{ interfaces.0.ip }}" +{% endfor %} + +stub-zone: + name: "10.in-addr.arpa" + stub-addr: "{{ interfaces.0.ip }}" +stub-zone: + name: "168.192.in-addr.arpa" + stub-addr: "{{ interfaces.0.ip }}" + +forward-zone: + name: "." # use for ALL queries + forward-addr: 74.82.42.42 # he.net + forward-addr: 2001:470:20::2 # he.net v6 + forward-addr: 8.8.8.8 # google.com + forward-addr: 2001:4860:4860::8888 # google.com v6 + forward-addr: 208.67.222.222 # opendns.com + forward-first: yes # try direct if forwarder fails diff --git a/needs_refactoring/dns/templates/zonefile.forward b/needs_refactoring/dns/templates/zonefile.forward new file mode 100644 index 0000000..6927000 --- /dev/null +++ b/needs_refactoring/dns/templates/zonefile.forward @@ -0,0 +1,17 @@ +$ORIGIN {{ item.name }}. +$TTL {{ item.ttl }} +@ IN SOA {{ item.soa.0.ns }} {{ item.soa.0.mail }} ( + {{ item.soa.0.serial }} ; serial + {{ item.soa.0.refresh }} ; refresh + {{ item.soa.0.retry }} + {{ item.soa.0.expire }} ; expire + {{ item.soa.0.ttl }} ; ttl + ) +; Name servers +{% for ns in item.nameservers %} +@ IN NS {{ item.soa.0.ns }} +{% endfor %} + +{% for record in item.records %} +{{ record.name }} IN {{ record.type }} {{ record.value }} +{% endfor %} diff --git a/needs_refactoring/dns/templates/zonefile.reverse b/needs_refactoring/dns/templates/zonefile.reverse new file mode 100644 index 0000000..f5e99af --- /dev/null +++ b/needs_refactoring/dns/templates/zonefile.reverse @@ -0,0 +1,17 @@ +$ORIGIN {{ item.name }}. +$TTL {{ item.ttl }} +@ IN SOA {{ item.soa.ns }} {{ item.soa.mail }} ( + {{ date }} ; serial + {{ item.soa.refresh }} ; refresh + {{ item.soa.retry }} + {{ item.soa.expire }} ; expire + {{ item.soa.ttl }} ; ttl + ) +; Name servers +{% for ns in item.nameservers %} +@ IN NS {{ ns }} +{% endfor %} + +{% for record in item.records %} +{{ record.name }} IN {{ record.type }} {{ record.value }} +{% endfor %} diff --git a/needs_refactoring/dns/vars/main.yml b/needs_refactoring/dns/vars/main.yml new file mode 100644 index 0000000..2354957 --- /dev/null +++ b/needs_refactoring/dns/vars/main.yml @@ -0,0 +1,53 @@ +dns_zones: + - name: "1wilson.org" + role: "master" + reverse_zone: False + peers: "" + ttl: "2d" + slaves: + - 213.239.242.238 + - 213.133.105.6 + - 193.47.99.3 + soa: + - ns: "ns.1wilson.org." + mail: "admin.1wilson.org." + serial: "2018122520" + refresh: "1d" + retry: "1d" + expire: "4w" + ttl: "1h" + nameservers: + - "ns.1wilson.org." + records: + - name: "ns" + type: "A" + value: "176.9.107.196" + - name: "*" + type: "A" + value: "176.9.107.196" + - name: "vmhost" + type: "CNAME" + value: "ns" + - name: "1wilson.local" + role: "master" + reverse_zone: True + ttl: "2d" + slaves: + - 10.1.0.254 + soa: + - ns: "ns.1wilson.local." + mail: "admin.1wilson.org." + serial: "2018121520" + refresh: "1d" + retry: "1d" + expire: "4w" + ttl: "1h" + nameservers: + - "ns.1wilson.local" + records: + - name: "ns" + type: "A" + value: "10.1.0.254" + - name: "git" + type: "A" + value: "10.1.0.10" diff --git a/needs_refactoring/docker-registry/files/config.yml b/needs_refactoring/docker-registry/files/config.yml new file mode 100644 index 0000000..3277f9a --- /dev/null +++ b/needs_refactoring/docker-registry/files/config.yml @@ -0,0 +1,18 @@ +version: 0.1 +log: + fields: + service: registry +storage: + cache: + blobdescriptor: inmemory + filesystem: + rootdirectory: /var/lib/registry +http: + addr: :5000 + headers: + X-Content-Type-Options: [nosniff] +health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 diff --git a/needs_refactoring/docker-registry/handlers/main.yml b/needs_refactoring/docker-registry/handlers/main.yml new file mode 100644 index 0000000..5af7e4f --- /dev/null +++ b/needs_refactoring/docker-registry/handlers/main.yml @@ -0,0 +1,7 @@ +- name: restart registry + command: docker stop registry + notify: restart registry (start) +- name: restart registry (start) + command: docker run -d -p 5000:5000 --restart=always --name registry \ + -v /etc/docker/registry/config.yml:/etc/docker/registry/config.yml \ + registry:2 diff --git a/needs_refactoring/docker-registry/tasks/main.yml b/needs_refactoring/docker-registry/tasks/main.yml new file mode 100644 index 0000000..897dd13 --- /dev/null +++ b/needs_refactoring/docker-registry/tasks/main.yml @@ -0,0 +1,10 @@ +- name: create config directory + file: + path: /etc/docker/registry + state: directory + mode: '0755' +- name: deploy registry config + copy: + src: config.yml + dest: /etc/docker/registry/config.yml + notify: restart registry diff --git a/needs_refactoring/git/tasks/main.yml b/needs_refactoring/git/tasks/main.yml new file mode 100644 index 0000000..6df4c13 --- /dev/null +++ b/needs_refactoring/git/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: OpenBSD git + import_tasks: openbsd.yml + when: ansible_distribution|lower == 'openbsd' diff --git a/needs_refactoring/git/tasks/openbsd.yml b/needs_refactoring/git/tasks/openbsd.yml new file mode 100644 index 0000000..aaa716e --- /dev/null +++ b/needs_refactoring/git/tasks/openbsd.yml @@ -0,0 +1,12 @@ +--- +- name: add gogs user + user: + name: _gogs +- name: install {{ item }} + community.general.openbsd_pkg: + name: {{ item }} + state: present + snapshot: "{{ force_openbsd_snapshot | default(false) }}" + with_items: + - git + - go diff --git a/needs_refactoring/hypervisor/files/install.site b/needs_refactoring/hypervisor/files/install.site new file mode 100755 index 0000000..d7cfcc0 --- /dev/null +++ b/needs_refactoring/hypervisor/files/install.site @@ -0,0 +1,2 @@ +#!/bin/sh +reboot diff --git a/needs_refactoring/hypervisor/files/site.tgz b/needs_refactoring/hypervisor/files/site.tgz new file mode 100644 index 0000000..c42d534 Binary files /dev/null and b/needs_refactoring/hypervisor/files/site.tgz differ diff --git a/needs_refactoring/hypervisor/handlers/main.yml b/needs_refactoring/hypervisor/handlers/main.yml new file mode 100644 index 0000000..6003c27 --- /dev/null +++ b/needs_refactoring/hypervisor/handlers/main.yml @@ -0,0 +1,24 @@ +--- +- name: bootstrap done + set_fact: + bootstrapped: true + changed_when: "bootstrapped == true" + notify: update vm.conf +- name: update vm.conf + template: + src: vm.conf + dest: /etc/vm.conf + owner: root + group: wheel + mode: '0640' + notify: unset bootstrap variable +- name: unset bootstrap variable + set_fact: + bootstrapped: false + changed_when: "bootstrapped == false" + notify: reload vmd +- name: reload vmd + service: + name: vmd + state: reloaded + enabled: true diff --git a/needs_refactoring/hypervisor/tasks/arch.yml b/needs_refactoring/hypervisor/tasks/arch.yml new file mode 100644 index 0000000..dfeb7ec --- /dev/null +++ b/needs_refactoring/hypervisor/tasks/arch.yml @@ -0,0 +1,26 @@ +- name: installing "{{ item }}" + package: + name: "{{ item }}" + state: present + with_items: + - libvirt + - ebtables + - dnsmasq + - bridge-utils + - openbsd-netcat +- name: start libvirtd + service: + name: libvirtd + state: started +- name: allow incoming INPUT traffic on virbr0 + iptables: + chain: INPUT + jump: ACCEPT + in_interface: virbr0 +- name: allow incoming FORWARD traffic on virbr0 + iptables: + chain: FORWARD + jump: ACCEPT + in_interface: virbr0 + with_items: + - 22 diff --git a/needs_refactoring/hypervisor/tasks/main.yml b/needs_refactoring/hypervisor/tasks/main.yml new file mode 100644 index 0000000..3514a42 --- /dev/null +++ b/needs_refactoring/hypervisor/tasks/main.yml @@ -0,0 +1,10 @@ +--- +- name: OpenBSD vmm configuration + import_tasks: openbsd.yml + when: ansible_distribution|lower == 'openbsd' +- name: Ubuntu libvirt configuration + import_tasks: ubuntu.yml + when: ansible_distribution|lower == 'ubuntu' +- name: arch linux libvirt configuration + import_tasks: arch.yml + when: ansible_distribution|lower == 'archlinux' diff --git a/needs_refactoring/hypervisor/tasks/openbsd.yml b/needs_refactoring/hypervisor/tasks/openbsd.yml new file mode 100644 index 0000000..b8743b0 --- /dev/null +++ b/needs_refactoring/hypervisor/tasks/openbsd.yml @@ -0,0 +1,126 @@ +--- +- name: ensure upobsd is installed + community.general.openbsd_pkg: + name: upobsd + state: present + snapshot: "{{ force_openbsd_snapshot | default(false) }}" +- name: network configuration + template: + src: "hostname.if" + dest: "/etc/hostname.{{ item.name }}" + owner: root + group: wheel + mode: "0640" + with_items: + - "{{ vm_interfaces }}" + when: interfaces is defined + notify: reload network +- name: vm directory + file: + path: "{{ vm_dir }}" + state: directory + mode: 0700 + owner: _vmd +- name: vm specific site package on mirror + copy: + src: site.tgz + dest: "{{ mirror_root }}/{{ item.0 }}/site{{ item.1.os_version | replace('.','') }}.tgz" + when: item.1.os_version in item.0 + with_nested: + - "{{ mirror_targets }}" + - "{{ vms }}" +- name: update OpenBSD mirror index.txt + shell: "cd {{ mirror_root }}/{{ item.0 }}/ && ls -ln > index.txt" + when: item.1.os_version in item.0 + with_nested: + - "{{ mirror_targets }}" + - "{{ vms }}" +- name: calculate vm mac addresses + shell: echo {{ item.0.name }} {{ item.1.network }}|md5|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/' + with_subelements: + - "{{ vms }}" + - interfaces + register: vm_lladdr + tags: vm.conf,lladdr +- name: prepare dhcpd lease + set_fact: + static: "{{ static|default([]) + [{ 'host': item.item.0.name, 'lladdr': item.stdout, 'ip': item.item.1.ip, 'network': item.item.1.network }] }}" + with_items: + - "{{ vm_lladdr.results }}" + tags: lladdr + changed_when: True + notify: update dhcpd.conf +- name: debug + debug: "msg={{ static }}" + tags: lladdr +- name: vm disks + stat: + path: "{{ vm_dir }}/{{ item.1.name }}" + get_checksum: False + get_md5: False + get_mime: False + get_attributes: False + with_subelements: + - "{{ vms }}" + - disks + register: st_disks +- name: create vm disks + command: "doas -u _vmd vmctl create {{ vm_dir }}/{{ item.item.1.name }} -s {{ item.item.1.size }}" + when: not item.stat.exists + with_items: + - "{{ st_disks.results }}" +- name: create auto_intall.conf from template + template: + src: auto_install.conf + dest: /tmp/auto_install.conf-{{ item.item.0.name }} + when: not item.stat.exists + with_items: + - "{{ st_disks.results }}" +- name: gather vms to create + find: + paths: /tmp/ + patterns: auto_install.conf-* + register: auto_install_vms +- name: create custom ramdisk for vm bootstrap + command: "upobsd -V {{ item.0.os_version }} -i {{ item.1.path }} -o /home/vm/bsd.rd-{{ item.0.name }}" + when: item.0.name in item.1.path + with_nested: + - "{{ vms }}" + - "{{ auto_install_vms.files }}" +- name: vm.conf + template: + src: vm.conf + dest: /etc/vm.conf + owner: root + group: wheel + mode: '0640' + tags: vm.conf + notify: reload vmd +- name: reload vmd + service: + name: vmd + state: reloaded + enabled: true + when: auto_install_vms is defined +- name: bootstrap vm + shell: "vmctl start {{ item.0.name }}-bootstrap -b /home/vm/bsd.rd-{{ item.0.name }} -d {{ vm_dir }}/{{ item.0.disks.0.name }} -n {{ item.0.interfaces.0.network }} && while ps auxww |grep \"vmd: {{ item.0.name }}-bootstrap\" | grep -v grep; do sleep 1; done" + when: item.0.name in item.1.path + with_nested: + - "{{ vms }}" + - "{{ auto_install_vms.files }}" + notify: bootstrap done +- name: delete temporary files + shell: rm -rf /tmp/auto_* + tags: delete +- name: "pf rules: pass all on vm bridge interfaces" + lineinfile: + path: /etc/anchors/ansible + line: "pass on {{ item.interface }}" + with_items: + - "{{ vm_network }}" + notify: reload pf +- name: "pf rules: pass all on tap interfaces" + lineinfile: + path: /etc/anchors/ansible + line: "pass on tap" + notify: reload pf diff --git a/needs_refactoring/hypervisor/tasks/ubuntu.yml b/needs_refactoring/hypervisor/tasks/ubuntu.yml new file mode 100644 index 0000000..5c8590e --- /dev/null +++ b/needs_refactoring/hypervisor/tasks/ubuntu.yml @@ -0,0 +1,11 @@ +--- +- name: install packages + package: + name: "{{ item }}" + state: installed + with_items: + - "qemu-kvm" + - "libvirt-bin" + - "ubuntu-vm-builder" + - "bridge-utils" + - "virtinst" diff --git a/needs_refactoring/hypervisor/templates/auto_install.conf b/needs_refactoring/hypervisor/templates/auto_install.conf new file mode 100644 index 0000000..37ad64f --- /dev/null +++ b/needs_refactoring/hypervisor/templates/auto_install.conf @@ -0,0 +1,15 @@ +System hostname = {{ item.item.0.name }} +Which network interface = vio0 +IPv4 address = dhcp +Password for root = $2b$10$e0PsIjZXaHoLwK6hMFFs3.i5nj/owWlGkLmnL2ZcjqITBc.upXka. +Setup a user = mw +Password for user = $2b$11$PBJOEz.9s0Q48acRRMq/BOk0jDI.v./evaBDYhvwqAHeGFKEyYtv. +Public ssh key for user = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8UWbtwvA8sOZHQKKD0Mdh4iEv9SaevzXvcIA/8I8XKi5iqn4D2Si4f3808XSeBJapUkXAhKEEG4KGcAaFb7eRPr1AQIS7bSzHBlN2RcgeItrUivfbzt+EQnC7O1cOaI0H8oJpIU8rmHIcC361zbzIpoWCgjNjyuPftRYZUE0UdrV9UOO8xM/V/2WluyKjEbt2rMeuaDseHx3pZ5QppI7XLanTG31g9HZutwlj5Q+8GSc1gxveAvWGWb2Xwb+7wAslOTFmwJuSIxyj8zBVXv/INm66f01vRspc2iYXD6CJq19y7Ma3R/2ibR/cPlhqCYLODO7qNcUXvJoCslQgC1kr mw@archimedes.wilson.local +What timezone are you in = Europe/Berlin +Unable to connect using https. Use http instead = yes +Location of sets = http +HTTP Server = {{ localmirror }} +Continue without verification = yes +Checksum test for site64.tgz failed. Continue anyway = yes +Unverified sets: site64.tgz. Continue without verification = yes +Set name(s) = -all bsd* base* etc* man* site* comp* diff --git a/needs_refactoring/hypervisor/templates/hostname.if b/needs_refactoring/hypervisor/templates/hostname.if new file mode 100644 index 0000000..ec92b15 --- /dev/null +++ b/needs_refactoring/hypervisor/templates/hostname.if @@ -0,0 +1,15 @@ +{% if item.ip is defined %} +{% if item.ip == "dhcp" %} +inet {{ item.ip }} description "{{ item.desc }}" +{% else %} +inet {{ item.ip }} {{ item.netmask }} NONE description "{{ item.desc }}" +{% endif %} +{% elif item.members is defined %} +{% for member in item.members %} +add {{ member }} +{% endfor %} +{% endif %} +{% if item.group is defined %} +group "{{ item.group }}" +{% endif %} +up diff --git a/needs_refactoring/hypervisor/templates/httpd.conf b/needs_refactoring/hypervisor/templates/httpd.conf new file mode 100644 index 0000000..fee8d60 --- /dev/null +++ b/needs_refactoring/hypervisor/templates/httpd.conf @@ -0,0 +1,27 @@ +# $OpenBSD: httpd.conf,v 1.20 2018/06/13 15:08:24 reyk Exp $ + +server "example.com" { + listen on * port 80 + location "/.well-known/acme-challenge/*" { + root "/acme" + request strip 2 + } + location * { + block return 302 "https://$HTTP_HOST$REQUEST_URI" + } +} + +server "example.com" { + listen on * tls port 443 + tls { + certificate "/etc/ssl/example.com.fullchain.pem" + key "/etc/ssl/private/example.com.key" + } + location "/pub/*" { + directory auto index + } + location "/.well-known/acme-challenge/*" { + root "/acme" + request strip 2 + } +} diff --git a/needs_refactoring/hypervisor/templates/libvirt.tf b/needs_refactoring/hypervisor/templates/libvirt.tf new file mode 100644 index 0000000..5bfb987 --- /dev/null +++ b/needs_refactoring/hypervisor/templates/libvirt.tf @@ -0,0 +1,76 @@ +provider "libvirt" { + uri = "{{ libvirt_uri }}" +} + +resource "libvirt_volume" "{{ os_image.name }}" { + name = "{{ os_image.name }}" + pool = "{{ libvirt_storage }}" + source = "{{ os_image.url }}" +} + +# cloud-init +resource "libvirt_cloudinit_disk" "cloudinit_ubuntu_resized" { + name = "cloudinit_ubuntu_resized.iso" + pool = "default" + + user_data = < +Ross Barnie +aflatto diff --git a/needs_refactoring/icinga2/icinga2/CHANGELOG.md b/needs_refactoring/icinga2/icinga2/CHANGELOG.md new file mode 100644 index 0000000..c700b80 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/CHANGELOG.md @@ -0,0 +1,32 @@ +# Change Log + +## [v0.2.0](https://github.com/Icinga/ansible-icinga2/tree/v0.2.0) (2018-07-20) +[Full Changelog](https://github.com/Icinga/ansible-icinga2/compare/v0.1.0...v0.2.0) + +**Implemented enhancements:** + +- Main configuration handling [\#9](https://github.com/Icinga/ansible-icinga2/issues/9) + +**Merged pull requests:** + +- i2\_constants refactor [\#13](https://github.com/Icinga/ansible-icinga2/pull/13) ([RossBarnie](https://github.com/RossBarnie)) +- Feature/main configuration [\#11](https://github.com/Icinga/ansible-icinga2/pull/11) ([bobapple](https://github.com/bobapple)) + +## [v0.1.0](https://github.com/Icinga/ansible-icinga2/tree/v0.1.0) (2018-05-28) +**Implemented enhancements:** + +- Add basic documentation [\#8](https://github.com/Icinga/ansible-icinga2/issues/8) +- Testing Environment [\#3](https://github.com/Icinga/ansible-icinga2/issues/3) +- Installation [\#2](https://github.com/Icinga/ansible-icinga2/issues/2) +- Repository Management [\#1](https://github.com/Icinga/ansible-icinga2/issues/1) + +**Merged pull requests:** + +- Add basic documentation [\#10](https://github.com/Icinga/ansible-icinga2/pull/10) ([bobapple](https://github.com/bobapple)) +- Add basic testing with Molecule and Travis-CI [\#7](https://github.com/Icinga/ansible-icinga2/pull/7) ([bobapple](https://github.com/bobapple)) +- Install Icinga 2 package [\#5](https://github.com/Icinga/ansible-icinga2/pull/5) ([bobapple](https://github.com/bobapple)) +- Add official Icinga repository [\#4](https://github.com/Icinga/ansible-icinga2/pull/4) ([bobapple](https://github.com/bobapple)) + + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/needs_refactoring/icinga2/icinga2/CONTRIBUTING.md b/needs_refactoring/icinga2/icinga2/CONTRIBUTING.md new file mode 100644 index 0000000..8e94d27 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/CONTRIBUTING.md @@ -0,0 +1,31 @@ +# Contributing +A roadmap of this project is located at https://github.com/Icinga/ansible-icinga2/milestones. Please consider +this roadmap when you start contributing to the project. + +Before starting your work on this module, you should [fork the project] to your GitHub account. This allows you to +freely experiment with your changes. When your changes are complete, submit a [pull request]. All pull requests will be +reviewed and merged if they suit some general guidelines: + +* Changes are located in a topic branch +* For new functionality, proper tests are written +* Changes should not solve certain problems on special environments +* Your change does not handle third party software for which dedicated Ansible role exist + * such as creating databases, installing webserver etc. + +## Branches +Choosing a proper name for a branch helps us identify its purpose and possibly find an associated bug or feature. +Generally a branch name should include a topic such as `fix` or `feature` followed by a description and an issue number +if applicable. Branches should have only changes relevant to a specific issue. + +``` +git checkout -b fix/service-template-typo-1234 +git checkout -b feature/config-handling-1235 +``` + +## Testing +If you add new functionality, make sure to write appropriate tests as well. A complete guide on how to run tests is +described in [TESTING.md](TESTING.md). + + +[fork the project]: https://help.github.com/articles/fork-a-repo/ +[pull request]: https://help.github.com/articles/using-pull-requests/ diff --git a/needs_refactoring/icinga2/icinga2/LICENSE b/needs_refactoring/icinga2/icinga2/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/needs_refactoring/icinga2/icinga2/README.md b/needs_refactoring/icinga2/icinga2/README.md new file mode 100644 index 0000000..6372b76 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/README.md @@ -0,0 +1,220 @@ +[![Build Status](https://api.travis-ci.org/Icinga/ansible-icinga2.svg?branch=master)](https://travis-ci.org/Icinga/ansible-icinga2) + +# Icinga 2 Role for Ansible + +Ansible role to install and configure [Icinga 2](https://www.icinga.com/products/icinga-2/). + +# This Role is in development stage + +## Setup + + +### Limitations + +The role is supported on the following platforms: + +* Icinga 2 >= v2.8 +* Ubuntu: 16.04, 18.04 +* Debian: 8,9 +* CeontOS/RHEL: 6,7 + +Other operating systems or versions may work but have not been tested. + +## Usage + +### Default behaviour + +By default this role adds the official [Icinga Repository](https://packages.icinga.com) to the system and installs the +`icinga2` package. + +``` yaml +- name: Default Example + hosts: localhost + roles: + - icinga2 +``` + +### Disable repository management + +You may choose to use your own or the systems default repositories. Repository management can be disabled: + +``` yaml +- name: Example without repository + hosts: all + roles: + - icinga2 + vars: + - i2_manage_repository: false +``` + +## Reference + +- [**Variables**](#variables) + - [Variable: i2_manage_repository](#variable-i2_manage_repository) + - [Variable: i2_manage_package](#variable-i2_manage_package) + - [Variable: i2_manage_service](#variable-i2_manage_service) + - [Variable: i2_apt_key](#variable-i2_apt_key) + - [Variable: i2_apt_url](#variable-i2_apt_url) + - [Variable: i2_i2_yum_key](#variable-i2_yum_key) + - [Variable: i2_i2_yum_url](#variable-i2_yum_url) + - [Variable: i2_confd](#variable-i2_confd) + - [Variable: i2_include_plugins](#variable-i2_include_plugins) + - [Variable: i2_custom_constants](#variable-i2_custom_constants) +- [**System specific variables**](#variables-os-specific) + - [Variable: i2_conf_dir](#variable-i2_conf_dir) + - [Variable: i2_user](#variable-i2_user) + - [Variable: i2_group](#variable-i2_group) + - [Variable: i2_lib_dir](#variable-i2_lib_dir) +- [**Handlers**](#handlers) + - [Handler: start icinga2](#handler-start-icinga2) + - [Handler: reload icinga2](#handler-reload-icinga2) + +### Variables + +#### Variable: `i2_manage_repository` +Whether to add the official [Icinga Repository](https://packages.icinga.com/) to the system or not. Defaults to `true`. + +#### Variable: `i2_manage_package` +Whether to install packages or not. Defaults to `true`. + +#### Variable: `i2_manage_service` +Whether to start, restart and reload the Icinga 2 on changes or not. Defaults to `true`. + +#### Variable: `i2_apt_key` +GPG key used to verify packages on APT based system. The key will be imported. Defaults to +`https://packages.icinga.com/icinga.key`. + +#### Variable: `i2_apt_url` +Repository URL for APT based systems. Defaults +to `deb http://packages.icinga.com/{{ ansible_distribution|lower }} icinga-{{ ansible_distribution_release }} main`. +This may be customized if you have a local mirror. + +#### Variable: `i2_yum_key` +GPG key used to verify packages on YUM based sytems. The key URL will be added to the repository file. Defaults to +`https://packages.icinga.com/icinga.key`. + +#### Variable: `i2_yum_url` +Repository URL for YUM based sytem. Defaults to `http://packages.icinga.com/epel/$releasever/release/`. This may be +customized if you have a local mirror. + +#### Variable: `i2_confd` +By default, configuration located in `/etc/icinga2/conf.d` is included. This list may be modified to include additional directories or set to `[]` to not include `conf.d` at all (e.g. on distributed installations). +Defaults to `[ "conf.d" ]`. + +#### Variable: `i2_include_plugins` +The [ITL](https://www.icinga.com/docs/icinga2/latest/doc/10-icinga-template-library/) comes with a set of +pre-configured check commands. This variable defines what to include. Defaults to +`["itl", "plugins", "plugins-contrib", "manubulon", "windows-plugins", "nscp"]` + +#### Variable: `i2_const_plugindir` +Set `PluginDir` constant. Defaults to `{{ i2_lib_dir }}/nagios/plugins`. + +#### Variable: `i2_const_manubulonplugindir` +Set `ManubulonPluginDir` constant. Defaults to `{{ i2_lib_dir }}/nagios/plugins`. + +#### Variable: `i2_const_plugincontribdir` +Set `PluginContribDir` constant. Defualts to `{{ i2_lib_dir }}/nagios/plugins`. + +#### Variable: `i2_const_nodename` +Set `NodeName` constant. Defaults to `{{ ansible_fqdn }}`. + +#### Variable: `i2_const_zonename` +Set `ZoneName` constant. Defaults to `{{ ansible_fqdn }}`. + +#### Variable: `i2_const_ticketsalt` +Set `TicketSalt` constant. Empty by default. + +#### Variable: `i2_custom_constants` +Add custom constants to `constants.conf`. Must be a dictionary. Defaults to: `{}` + +Some default required values are specified in `i2_default_constants` and merged with this variable. Use this variable to override these default values, or add your own constants. + +Default values of `i2_default_constants`: +```yaml + PluginDir: "{{ i2_lib_dir }}/nagios/plugins" + ManubulonPluginDir: "{{ i2_lib_dir }}/nagios/plugins" + PluginContribDir: "{{ i2_lib_dir }}/nagios/plugins" + NodeName: "{{ ansible_fqdn }}" + ZoneName: "{{ ansible_fqdn }}" + TicketSalt: "" +``` + +Example usage: +```yaml + vars: + - i2_constants: + TicketSalt: "My ticket salt" + Foo: "bar" +``` + +### System specific variables +The following variables are system specific and don't need to be overwritten in most cases. Be careful when making +changes to any of these variables. + +#### Variable: `i2_conf_dir` +Base Icinga 2 configuration directory. Defaults to `/etc/icinga2`. + +#### Variable: `i2_user` +Icinga 2 running as user. Default depends on OS. + +#### Variable: `i2_group` +Icinga 2 running as group. Default depends on OS. + +#### Variable: `i2_lib_dir` +Lib dir. Default depends on OS. + +### Feature Usage + +#### Variable: `i2_custom_features` +Features are maintained over the dictionary `i2_custom_features`. +By default features won't be managed until `i2_custom_features` has further values. + +Example usage: + +```yaml +vars: + - i2_custom_features: + ApiListener: #ObjectType + api: #ObjectName + accept_command: true #ObjectAttribute + accept_config: true #ObjectAttribute + GraphiteWriter: + graphite: + host: "127.0.0.1" + port: "2004" +``` + +#### Variable: `i2_remove_unmanaged_features` +The variable `i2_remove_unmanaged_features` change the behaviour of the feature handling. +It will remove all **unmanged** `.conf` files from the directory `/etc/icinga2/features-enabled` and let you manage only your defined features. + +### Handlers + +#### Handler: `start icinga2` +This handler starts Icinga 2. It is only used to make sure Icinga 2 is running. You can prevent this handler from +being triggered by setting `i2_manage_service` to false. + +#### Handler: `reload icinga2` +This handler reloads Icinga 2 when configuration changes. You can prevent this handler from being triggered by setting +`i2_manage_service` to false. + +## Development +A roadmap of this project is located at https://github.com/Icinga/ansible-icinga2/milestones. Please consider this +roadmap when you start contributing to the project. + +### Contributing +When contributing several steps such as pull requests and proper testing implementations are required. Find a detailed +step by step guide in [CONTRIBUTING.md](CONTRIBUTING.md). + +### Testing +Testing is essential in our workflow to ensure a good quality. We use Molecule to test all +components of this role. For a detailed description see [TESTING.md](TESTING.md). + +## Release Notes +When releasing new versions we refer to [SemVer 1.0.0](http://semver.org/spec/v1.0.0.html) for version numbers. All steps required when creating a new +release are described in [RELEASE.md](RELEASE.md) + +See also [CHANGELOG.md](CHANGELOG.md) + +## Authors +[AUTHORS](AUTHORS) is generated on each release. diff --git a/needs_refactoring/icinga2/icinga2/RELEASE.md b/needs_refactoring/icinga2/icinga2/RELEASE.md new file mode 100644 index 0000000..b4a375a --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/RELEASE.md @@ -0,0 +1,50 @@ +# Release Workflow +Before submitting a new release, make sure all relevant pull requests and local branches have been merged to the `master` +branch. All tests must pass before a release is tagged. + + +## Testing +Make sure tests pass before starting with a release. See [TESTING.md](TESTING.md) for more information. + +## 1. AUTHORS +Update the [AUTHORS](AUTHORS) and [.mailmap](.mailmap) file + +``` bash +git checkout master +git log --use-mailmap | grep ^Author: | cut -f2- -d' ' | sort | uniq > AUTHORS +git commit -am "Update AUTHORS" +``` + +## 2. Changelog +Install [github-changelog-generator](https://github.com/skywinder/github-changelog-generator) +```bash +gem install github_changelog_generator +``` + +Generate [CHANGELOG.md](CHANGELOG.md) +```bash +github_changelog_generator -t --future-release=v1.0.0 +``` + +## 3. Git Tag +Commit all changes to the `master` branch + +``` bash +git commit -v -a -m "Release version " +git push +``` + +Tag the release + +``` bash +git tag -m "Version " v +``` + +Push tags + +``` bash +git push --tags +``` + +## Ansible Galaxy +The role is uploaded automatically to [Ansible Galaxy](https://galaxy.ansible.com/). \ No newline at end of file diff --git a/needs_refactoring/icinga2/icinga2/TESTING.md b/needs_refactoring/icinga2/icinga2/TESTING.md new file mode 100644 index 0000000..7ec9f03 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/TESTING.md @@ -0,0 +1,35 @@ +# TESTING +This role includes everything necessary to be tested with [Molecule](https://molecule.readthedocs.io/en/latest/). The +[installation documentation](https://molecule.readthedocs.io/en/latest/installation.html) provides +a great walk-through to get started. + +## Running tests +Run all tests (all scenarios on all platforms): + +``` shell +molecule test --all +``` + +Run specific scenario (scenario `default` is used by default) + +``` shell +molecule test -s default +``` + +Don't destroy container after running the tests: + +``` shell +molecule test --destroy never +``` + +Run only linter + +``` shell +molecule lint +``` + +Run only syntax checks + +``` shell +molecule syntax +``` \ No newline at end of file diff --git a/needs_refactoring/icinga2/icinga2/defaults/main.yml b/needs_refactoring/icinga2/icinga2/defaults/main.yml new file mode 100644 index 0000000..7445a04 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/defaults/main.yml @@ -0,0 +1,20 @@ +--- +i2_manage_repository: true +i2_apt_key: "https://packages.icinga.com/icinga.key" +i2_apt_url: "deb http://packages.icinga.com/{{ ansible_distribution|lower }} icinga-{{ ansible_distribution_release }} main" +i2_yum_key: "https://packages.icinga.com/icinga.key" +i2_yum_url: "http://packages.icinga.com/epel/$releasever/release/" +i2_manage_package: true +i2_manage_service: true +i2_remove_unmanaged_features: false +i2_confd: + - "conf.d" +i2_include_plugins: + - "itl" + - "plugins" + - "plugins-contrib" + - "manubulon" + - "windows-plugins" + - "nscp" +i2_custom_constants: {} +i2_custom_features: {} diff --git a/needs_refactoring/icinga2/icinga2/handlers/main.yml b/needs_refactoring/icinga2/icinga2/handlers/main.yml new file mode 100644 index 0000000..1dd2b9b --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/handlers/main.yml @@ -0,0 +1,22 @@ +--- +- name: start icinga2 + become: yes + service: + name: icinga2 + state: started + enabled: yes + when: i2_manage_service + +- name: reload icinga2 + become: yes + service: + name: icinga2 + state: reloaded + when: i2_manage_service + +- name: restart icinga2 + become: yes + service: + name: icinga2 + state: restarted + when: i2_manage_service diff --git a/needs_refactoring/icinga2/icinga2/meta/main.yml b/needs_refactoring/icinga2/icinga2/meta/main.yml new file mode 100644 index 0000000..61eb821 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/meta/main.yml @@ -0,0 +1,28 @@ +--- +galaxy_info: + author: "Icinga Development Team " + description: "Install and configure Icinga 2" + company: "Icinga GmbH" + license: "license (Apache)" + min_ansible_version: 2.3.2 + platforms: + - name: EL + versions: + - 6 + - 7 + - name: Debian + versions: + - 8 + - 9 + - name: Ubuntu + versions: + - 16.04 + - 18.04 + categories: + - system + galaxy_tags: + - monitoring + - icinga + - icinga2 + +dependencies: [] diff --git a/needs_refactoring/icinga2/icinga2/molecule/default/Dockerfile.j2 b/needs_refactoring/icinga2/icinga2/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..19692c2 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/molecule/default/Dockerfile.j2 @@ -0,0 +1,14 @@ +# Molecule managed + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get upgrade -y && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python2-dnf bash && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum update -y && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper update -y && zypper install -y python sudo bash python-xml && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi diff --git a/needs_refactoring/icinga2/icinga2/molecule/default/INSTALL.rst b/needs_refactoring/icinga2/icinga2/molecule/default/INSTALL.rst new file mode 100644 index 0000000..e26493b --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/molecule/default/INSTALL.rst @@ -0,0 +1,16 @@ +******* +Install +******* + +Requirements +============ + +* Docker Engine +* docker-py + +Install +======= + +.. code-block:: bash + + $ sudo pip install docker-py diff --git a/needs_refactoring/icinga2/icinga2/molecule/default/create.yml b/needs_refactoring/icinga2/icinga2/molecule/default/create.yml new file mode 100644 index 0000000..8fb9c4f --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/molecule/default/create.yml @@ -0,0 +1,81 @@ +--- +- name: Create + hosts: localhost + connection: local + gather_facts: false + no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}" + tasks: + - name: Log into a Docker registry + docker_login: + username: "{{ item.registry.credentials.username }}" + password: "{{ item.registry.credentials.password }}" + email: "{{ item.registry.credentials.email | default(omit) }}" + registry: "{{ item.registry.url }}" + docker_host: "{{ item.docker_host | default('unix://var/run/docker.sock') }}" + with_items: "{{ molecule_yml.platforms }}" + when: + - item.registry is defined + - item.registry.credentials is defined + - item.registry.credentials.username is defined + + - name: Create Dockerfiles from image names + template: + src: "{{ molecule_scenario_directory }}/Dockerfile.j2" + dest: "{{ molecule_ephemeral_directory }}/Dockerfile_{{ item.image | regex_replace('[^a-zA-Z0-9_]', '_') }}" + with_items: "{{ molecule_yml.platforms }}" + register: platforms + + - name: Discover local Docker images + docker_image_facts: + name: "molecule_local/{{ item.item.name }}" + docker_host: "{{ item.item.docker_host | default('unix://var/run/docker.sock') }}" + with_items: "{{ platforms.results }}" + register: docker_images + + - name: Build an Ansible compatible image + docker_image: + path: "{{ molecule_ephemeral_directory }}" + name: "molecule_local/{{ item.item.image }}" + docker_host: "{{ item.item.docker_host | default('unix://var/run/docker.sock') }}" + dockerfile: "{{ item.item.dockerfile | default(item.invocation.module_args.dest) }}" + force: "{{ item.item.force | default(true) }}" + with_items: "{{ platforms.results }}" + when: platforms.changed or docker_images.results | map(attribute='images') | select('equalto', []) | list | count >= 0 + + - name: Create docker network(s) + docker_network: + name: "{{ item }}" + docker_host: "{{ item.docker_host | default('unix://var/run/docker.sock') }}" + state: present + with_items: "{{ molecule_yml.platforms | molecule_get_docker_networks }}" + + - name: Create molecule instance(s) + docker_container: + name: "{{ item.name }}" + docker_host: "{{ item.docker_host | default('unix://var/run/docker.sock') }}" + hostname: "{{ item.name }}" + image: "molecule_local/{{ item.image }}" + state: started + recreate: false + log_driver: json-file + command: "{{ item.command | default('bash -c \"while true; do sleep 10000; done\"') }}" + privileged: "{{ item.privileged | default(omit) }}" + volumes: "{{ item.volumes | default(omit) }}" + capabilities: "{{ item.capabilities | default(omit) }}" + exposed_ports: "{{ item.exposed_ports | default(omit) }}" + published_ports: "{{ item.published_ports | default(omit) }}" + ulimits: "{{ item.ulimits | default(omit) }}" + networks: "{{ item.networks | default(omit) }}" + dns_servers: "{{ item.dns_servers | default(omit) }}" + register: server + with_items: "{{ molecule_yml.platforms }}" + async: 7200 + poll: 0 + + - name: Wait for instance(s) creation to complete + async_status: + jid: "{{ item.ansible_job_id }}" + register: docker_jobs + until: docker_jobs.finished + retries: 300 + with_items: "{{ server.results }}" diff --git a/needs_refactoring/icinga2/icinga2/molecule/default/destroy.yml b/needs_refactoring/icinga2/icinga2/molecule/default/destroy.yml new file mode 100644 index 0000000..2c2bf11 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/molecule/default/destroy.yml @@ -0,0 +1,32 @@ +--- +- name: Destroy + hosts: localhost + connection: local + gather_facts: false + no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}" + tasks: + - name: Destroy molecule instance(s) + docker_container: + name: "{{ item.name }}" + docker_host: "{{ item.docker_host | default('unix://var/run/docker.sock') }}" + state: absent + force_kill: "{{ item.force_kill | default(true) }}" + register: server + with_items: "{{ molecule_yml.platforms }}" + async: 7200 + poll: 0 + + - name: Wait for instance(s) deletion to complete + async_status: + jid: "{{ item.ansible_job_id }}" + register: docker_jobs + until: docker_jobs.finished + retries: 300 + with_items: "{{ server.results }}" + + - name: Delete docker network(s) + docker_network: + name: "{{ item }}" + docker_host: "{{ item.docker_host | default('unix://var/run/docker.sock') }}" + state: absent + with_items: "{{ molecule_yml.platforms | molecule_get_docker_networks }}" diff --git a/needs_refactoring/icinga2/icinga2/molecule/default/molecule.yml b/needs_refactoring/icinga2/icinga2/molecule/default/molecule.yml new file mode 100644 index 0000000..aaee021 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/molecule/default/molecule.yml @@ -0,0 +1,33 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: + name: yamllint +platforms: + - name: centos7 + image: solita/centos-systemd:7 + command: /sbin/init + capabilities: + - SYS_ADMIN + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + - name: ubuntu16 + image: solita/ubuntu-systemd:16.04 + command: /sbin/init + capabilities: + - SYS_ADMIN + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro +provisioner: + name: ansible + lint: + name: ansible-lint +scenario: + name: default +verifier: + name: testinfra + lint: + name: flake8 + enabled: true diff --git a/needs_refactoring/icinga2/icinga2/molecule/default/playbook.yml b/needs_refactoring/icinga2/icinga2/molecule/default/playbook.yml new file mode 100644 index 0000000..14fdca9 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/molecule/default/playbook.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - { role: ansible-icinga2, i2_custom_features: { GraphiteWriter: { graphite: { host: "127.0.0.2" } } } } diff --git a/needs_refactoring/icinga2/icinga2/molecule/default/prepare.yml b/needs_refactoring/icinga2/icinga2/molecule/default/prepare.yml new file mode 100644 index 0000000..1904df9 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/molecule/default/prepare.yml @@ -0,0 +1,5 @@ +--- +- name: Prepare + hosts: all + gather_facts: true + tasks: [] diff --git a/needs_refactoring/icinga2/icinga2/molecule/default/tests/test_default.py b/needs_refactoring/icinga2/icinga2/molecule/default/tests/test_default.py new file mode 100644 index 0000000..126184b --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/molecule/default/tests/test_default.py @@ -0,0 +1,30 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_icinga_repository_file(host): + if host.system_info.distribution == 'centos': + i2_repo = host.file('/etc/yum.repos.d/ICINGA-release.repo') + else: + i2_repo = host.file('/etc/apt/sources.list.d/packages_icinga_com_ubuntu.list') + + assert i2_repo.exists + assert i2_repo.user == 'root' + assert i2_repo.group == 'root' + + +def test_icinga2_is_installed(host): + i2_package = host.package("icinga2") + + assert i2_package.is_installed + + +def test_icinga2_running_and_enabled(host): + i2_service = host.service("icinga2") + + assert i2_service.is_running + assert i2_service.is_enabled diff --git a/needs_refactoring/icinga2/icinga2/molecule/default/tests/test_default.pyc b/needs_refactoring/icinga2/icinga2/molecule/default/tests/test_default.pyc new file mode 100644 index 0000000..322a5ee Binary files /dev/null and b/needs_refactoring/icinga2/icinga2/molecule/default/tests/test_default.pyc differ diff --git a/needs_refactoring/icinga2/icinga2/tasks/icinga2-Debian.yml b/needs_refactoring/icinga2/icinga2/tasks/icinga2-Debian.yml new file mode 100644 index 0000000..3cfdeee --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/tasks/icinga2-Debian.yml @@ -0,0 +1,29 @@ +--- +- name: Debian - Install apt-transport-https + become: yes + apt: + name: apt-transport-https + state: present + when: i2_manage_repository + +- name: Debian - Add Icinga 2 repository key + become: yes + apt_key: + url: "{{ i2_apt_key }}" + state: present + when: i2_manage_repository and i2_apt_key + +- name: Debian - Add Icinga 2 repository + become: yes + apt_repository: + repo: "{{ i2_apt_url }}" + state: present + when: i2_manage_repository + +- name: Debian - Ensure icinga2 is installed + become: yes + apt: + name: icinga2 + state: present + notify: start icinga2 + when: i2_manage_package diff --git a/needs_refactoring/icinga2/icinga2/tasks/icinga2-RedHat.yml b/needs_refactoring/icinga2/icinga2/tasks/icinga2-RedHat.yml new file mode 100644 index 0000000..1e13db5 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/tasks/icinga2-RedHat.yml @@ -0,0 +1,18 @@ +--- +- name: RedHat - Add Icinga 2 repository + become: yes + yum_repository: + name: ICINGA-release + description: Icinga packages for EL + baseurl: "{{ i2_yum_url }}" + gpgkey: "{{ i2_yum_key }}" + gpgcheck: yes + when: i2_manage_repository + +- name: RedHat - Ensure icinga2 is installed + become: yes + yum: + name: icinga2 + state: present + notify: start icinga2 + when: i2_manage_package diff --git a/needs_refactoring/icinga2/icinga2/tasks/icinga2-config.yml b/needs_refactoring/icinga2/icinga2/tasks/icinga2-config.yml new file mode 100644 index 0000000..9bc7273 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/tasks/icinga2-config.yml @@ -0,0 +1,45 @@ +--- +- name: Create conf.d directory + become: yes + file: + dest: "{{ i2_conf_dir }}/{{ item }}" + state: directory + owner: "{{ i2_user }}" + group: "{{ i2_group }}" + with_items: "{{ i2_confd }}" + +- name: Manage main Icinga 2 configuration + become: yes + template: + src: icinga2.conf.j2 + dest: "{{ i2_conf_dir }}/icinga2.conf" + owner: "{{ i2_user }}" + group: "{{ i2_group }}" + mode: 0644 + notify: reload icinga2 + +- name: Check for constants sample file + stat: + path: "{{ i2_conf_dir }}/constants.conf-sample" + register: sample_file + +- name: Copy original Icinga 2 config to sample + become: yes + copy: + remote_src: true + src: "{{ i2_conf_dir }}/constants.conf" + dest: "{{ i2_conf_dir }}/constants.conf-sample" + owner: "{{ i2_user }}" + group: "{{ i2_group }}" + mode: 0644 + when: not sample_file.stat.exists + +- name: Manage Icinga 2 constants + become: yes + template: + src: constants.conf.j2 + dest: "{{ i2_conf_dir }}/constants.conf" + owner: "{{ i2_user }}" + group: "{{ i2_group }}" + mode: 0644 + notify: reload icinga2 diff --git a/needs_refactoring/icinga2/icinga2/tasks/icinga2-features.yml b/needs_refactoring/icinga2/icinga2/tasks/icinga2-features.yml new file mode 100644 index 0000000..7a16878 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/tasks/icinga2-features.yml @@ -0,0 +1,45 @@ +--- +- name: collect all enabled features + become: yes + find: + paths: "{{ i2_features_enabled_dir }}/" + patterns: '*.conf' + file_type: any + register: enabled_features + when: + - i2_remove_unmanaged_features + +- name: generate enabled feature configuration + become: yes + template: + src: templates/feature-generic-template.conf.j2 + dest: "{{ i2_features_enabled_dir }}/{{ item.key }}.conf" + owner: "{{ i2_user }}" + group: "{{ i2_group }}" + mode: 0644 + with_dict: "{{ i2_features }}" + register: managed_features + notify: + - restart icinga2 + +- name: set fact enabled_files + set_fact: + enabled_files: "{{ enabled_files|default([]) + [ item.path ] }}" + loop: "{{ enabled_features.files }}" + when: + - i2_remove_unmanaged_features + +- name: Set Fact managed_features_files + set_fact: + managed_feature_files: "{{ item.dest }}" + with_items: "{{ managed_features.results }}" + when: + - i2_remove_unmanaged_features + +- name: removing unmanaged features + file: + path: "{{ item }}" + state: absent + with_items: "{{ enabled_files|default([]) }}" + when: + - item not in managed_feature_files and i2_remove_unmanaged_features diff --git a/needs_refactoring/icinga2/icinga2/tasks/icinga2.yml b/needs_refactoring/icinga2/icinga2/tasks/icinga2.yml new file mode 100644 index 0000000..8b960ca --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/tasks/icinga2.yml @@ -0,0 +1,8 @@ +--- +- name: Include specific Icinga 2 + include: icinga2-Debian.yml + when: ansible_os_family == 'Debian' + +- name: Include specific Icinga 2 + include: icinga2-RedHat.yml + when: ansible_os_family == 'RedHat' diff --git a/needs_refactoring/icinga2/icinga2/tasks/main.yml b/needs_refactoring/icinga2/icinga2/tasks/main.yml new file mode 100644 index 0000000..14edd12 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/tasks/main.yml @@ -0,0 +1,29 @@ +--- +- name: Include OS specific vars + include_vars: "{{ansible_os_family}}.yml" + tags: + - feature-handler + - config + +- name: include icinga2.yml + include: icinga2.yml + tags: + - install + +- name: include icinga2-config.yml + include: icinga2-config.yml + tags: + - config + +- name: include icinga2-features.yml + include_tasks: icinga2-features.yml + when: i2_features|flatten|length > 0 + tags: + - feature-handler + +- name: Make sure Icinga 2 is started + service: + name: icinga2 + state: started + enabled: yes + when: i2_manage_service diff --git a/needs_refactoring/icinga2/icinga2/templates/constants.conf.j2 b/needs_refactoring/icinga2/icinga2/templates/constants.conf.j2 new file mode 100644 index 0000000..8ca0e87 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/templates/constants.conf.j2 @@ -0,0 +1,10 @@ +// {{ ansible_managed }} + +/** + * This file defines global constants which can be used in + * the other configuration files. + */ + +{% for name, value in i2_constants.items() %} +const {{ name }} = "{{ value }}" +{% endfor %} diff --git a/needs_refactoring/icinga2/icinga2/templates/feature-generic-template.conf.j2 b/needs_refactoring/icinga2/icinga2/templates/feature-generic-template.conf.j2 new file mode 100644 index 0000000..850155e --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/templates/feature-generic-template.conf.j2 @@ -0,0 +1,8 @@ +// {{ ansible_managed }} +{% import 'object_attributes.j2' as attributes %} + +{% for object_name, params in item.value.iteritems() %} +object {{ item.key }} "{{ object_name }}" { + {{ attributes.attrs(params) -}} +} +{% endfor %} diff --git a/needs_refactoring/icinga2/icinga2/templates/icinga2.conf.j2 b/needs_refactoring/icinga2/icinga2/templates/icinga2.conf.j2 new file mode 100644 index 0000000..cf74968 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/templates/icinga2.conf.j2 @@ -0,0 +1,48 @@ +// {{ ansible_managed }} + +/** + * Icinga 2 configuration file + * - this is where you define settings for the Icinga application including + * which hosts/services to check. + * + * For an overview of all available configuration options please refer + * to the documentation that is distributed as part of Icinga 2. + */ + +/** + * The constants.conf defines global constants. + */ +include "constants.conf" + +/** + * The zones.conf defines zones for a cluster setup. + * Not required for single instance setups. + */ +include "zones.conf" + +/** + * The Icinga Template Library (ITL) provides a number of useful templates + * and command definitions. + * Common monitoring plugin command definitions are included separately. + */ +{% for plugins in i2_include_plugins %} +include <{{ plugins }}> +{% endfor %} + +/** + * The features-available directory contains a number of configuration + * files for features which can be enabled and disabled using the + * icinga2 feature enable / icinga2 feature disable CLI commands. + * These commands work by creating and removing symbolic links in + * the features-enabled directory. + */ +include "features-enabled/*.conf" + +/** + * Although in theory you could define all your objects in this file + * the preferred way is to create separate directories and files in the conf.d + * directory. Each of these files must have the file extension ".conf". + */ +{% for include_dir in i2_confd %} +include_recursive "{{ include_dir }}" +{% endfor %} diff --git a/needs_refactoring/icinga2/icinga2/templates/object_attributes.j2 b/needs_refactoring/icinga2/icinga2/templates/object_attributes.j2 new file mode 100644 index 0000000..b28c016 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/templates/object_attributes.j2 @@ -0,0 +1,33 @@ +{% macro attrs(map, exclude=[]) %} +{% for k, v in map.iteritems() %} +{%- if v is mapping %} +{{ mapdict(k,v) | indent(width=2)}} +{%- else %} +{{ eval_value(k,v) }} +{% endif %} +{% endfor %} +{% endmacro %} + +{% macro mapdict(key,dictionary) %} +{{ key }} = { +{% for i, w in dictionary.iteritems() %} +{%- if w is mapping %} +{{ mapdict(i,w) | indent(width=2)}} +{%- else %} +{{ eval_value(i,w) }} +{% endif %} +{% endfor %} +} +{% endmacro %} + +{% macro eval_value(key,val) %} +{%- if val is iterable and val is not string %} +{{ key }} = [ "{{ val | map('quote') | join('", "') }}" ] +{%- elif val is match('^\d+(ms|s|h|d)?$') %} +{{ key }} = {{ val }} +{%- elif val | bool == False and val | string == "false" %} +{{ key }} = {{ val }} +{%- else %} +{{ key }} = "{{ val | quote }}" +{%- endif %} +{% endmacro %} diff --git a/needs_refactoring/icinga2/icinga2/tests/inventory b/needs_refactoring/icinga2/icinga2/tests/inventory new file mode 100644 index 0000000..bcb66f4 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/tests/inventory @@ -0,0 +1,9 @@ +[all] +icinga2 +centos7 + +[debian] +icinga2 + +[rhel] +centos7 \ No newline at end of file diff --git a/needs_refactoring/icinga2/icinga2/tests/test.yml b/needs_refactoring/icinga2/icinga2/tests/test.yml new file mode 100644 index 0000000..c8f547c --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: all + remote_user: root + roles: + - { role: ansible-icinga2, i2_custom_features: { GraphiteWriter: { graphite: { host: "127.0.0.2" } } } } diff --git a/needs_refactoring/icinga2/icinga2/vars/Debian.yml b/needs_refactoring/icinga2/icinga2/vars/Debian.yml new file mode 100644 index 0000000..a78ed1a --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/vars/Debian.yml @@ -0,0 +1,4 @@ +--- +i2_user: nagios +i2_group: nagios +i2_lib_dir: /usr/lib diff --git a/needs_refactoring/icinga2/icinga2/vars/RedHat.yml b/needs_refactoring/icinga2/icinga2/vars/RedHat.yml new file mode 100644 index 0000000..d8c22ca --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/vars/RedHat.yml @@ -0,0 +1,4 @@ +--- +i2_user: icinga +i2_group: icinga +i2_lib_dir: /usr/lib64 diff --git a/needs_refactoring/icinga2/icinga2/vars/main.yml b/needs_refactoring/icinga2/icinga2/vars/main.yml new file mode 100644 index 0000000..d345759 --- /dev/null +++ b/needs_refactoring/icinga2/icinga2/vars/main.yml @@ -0,0 +1,18 @@ +--- +i2_conf_dir: "/etc/icinga2" +i2_features_available_dir: "{{ i2_conf_dir }}/features-available" +i2_features_enabled_dir: "{{ i2_conf_dir }}/features-enabled" +i2_default_constants: + PluginDir: "{{ i2_lib_dir }}/nagios/plugins" + ManubulonPluginDir: "{{ i2_lib_dir }}/nagios/plugins" + PluginContribDir: "{{ i2_lib_dir }}/nagios/plugins" + NodeName: "{{ ansible_fqdn }}" + ZoneName: "{{ ansible_fqdn }}" + TicketSalt: "" +i2_constants: "{{ i2_default_constants | combine(i2_custom_constants) }}" +i2_features: "{{ i2_custom_features }}" +i2_custom_features: + ApiListener: #ObjectType + api: #ObjectName + accept_command: true #ObjectAttribute + accept_config: true #ObjectAttribute diff --git a/needs_refactoring/icinga2/vspheredb/files/config.ini b/needs_refactoring/icinga2/vspheredb/files/config.ini new file mode 100644 index 0000000..d89eb0e --- /dev/null +++ b/needs_refactoring/icinga2/vspheredb/files/config.ini @@ -0,0 +1,2 @@ +[db] +resource = "vspheredb" diff --git a/needs_refactoring/icinga2/vspheredb/files/icinga-vspheredb.service b/needs_refactoring/icinga2/vspheredb/files/icinga-vspheredb.service new file mode 100644 index 0000000..e6a109f --- /dev/null +++ b/needs_refactoring/icinga2/vspheredb/files/icinga-vspheredb.service @@ -0,0 +1,19 @@ +[Unit] +Description=Icinga vSphereDB Daemon +Documentation=https://icinga.com/docs/icinga-vsphere/latest/ +Wants=network.target + +[Service] +Type=simple +;ExecStart=/usr/bin/icingacli vspheredb daemon run +; For debugging purposes: +ExecStart=/usr/bin/icingacli vspheredb daemon run --trace --debug +User=apache + +WatchdogSec=10 + +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=multi-user.target diff --git a/needs_refactoring/icinga2/vspheredb/tasks/main.yml b/needs_refactoring/icinga2/vspheredb/tasks/main.yml new file mode 100644 index 0000000..3144607 --- /dev/null +++ b/needs_refactoring/icinga2/vspheredb/tasks/main.yml @@ -0,0 +1,69 @@ +--- +- name: Install dependencies + package: + name: "{{ item }}" + state: installed + loop: "{{ packages }}" + +- name: Download modules from github + git: + repo: "https://github.com/Icinga/icingaweb2-module-{{ item.name }}.git" + dest: "{{ modules_dir }}/{{ item.name }}" + update: no + version: "{{ item.version }}" + loop: "{{ modules }}" + ignore_errors: yes + tags: minimal + +- name: enable modules + shell: "icingacli module enable {{ item.name }}" + loop: "{{ modules }}" + tags: minimal + +- name: check systemd service file exists + stat: + path: /etc/systemd/system/icinga-vspheredb.service + register: stat_systemd + ignore_errors: yes + +- name: copy systemd service file + copy: + src: icinga-vspheredb.service + dest: /etc/systemd/system/icinga-vspheredb.service + when: stat_systemd.stat.exists == False + +- name: systemctl daemon-reload + command: "systemctl daemon-reload" + when: stat_systemd.stat.exists == False + +- name: create mysql dbs + mysql_db: + name: "{{ item.name }}" + state: present + target: "{{ item.schema }}" + loop: "{{ mysql_dbs }}" + register: dbs_created +- name: create mysql dbs + mysql_db: + name: "{{ item.name }}" + state: import + target: "{{ item.schema }}" + loop: "{{ mysql_dbs }}" + when: dbs_created.changed + +- name: create mysql users + mysql_user: + name: "{{ item.user }}" + password: "{{ item.password }}" + priv: "{{ item.name }}.*:ALL" + state: present + loop: "{{ mysql_dbs }}" + +- name: create vspheredb config dir + file: + path: /etc/icingaweb2/modules/vspheredb/ + state: directory +- name: copy vspheredb config + copy: + src: config.ini + dest: /etc/icingaweb2/modules/vspheredb/config.ini diff --git a/needs_refactoring/icinga2/vspheredb/vars/main.yml b/needs_refactoring/icinga2/vspheredb/vars/main.yml new file mode 100644 index 0000000..8c33dc1 --- /dev/null +++ b/needs_refactoring/icinga2/vspheredb/vars/main.yml @@ -0,0 +1,30 @@ +--- +modules_dir: "/usr/share/icingaweb2/modules" + +modules: + - name: reactbundle + version: v0.7.0 + - name: ipl + version: v0.4.0 + - name: incubator + version: v0.5.0 + - name: director + version: v1.7.1 + - name: vspheredb + version: v1.0.3 + +packages: + - rh-php71-php-process + - rh-php71-php-soap + - git + - python2-PyMySQL + +mysql_dbs: + - name: director + user: director + password: director + schema: "{{ modules_dir }}/director/schema/mysql.sql" + - name: vspheredb + user: vspheredb + password: vspheredb + schema: "{{ modules_dir }}/vspheredb/schema/mysql.sql" diff --git a/needs_refactoring/ipsec/tasks/main.yml b/needs_refactoring/ipsec/tasks/main.yml new file mode 100644 index 0000000..58313af --- /dev/null +++ b/needs_refactoring/ipsec/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: OpenBSD ipsec + import_tasks: openbsd.yml + when: ansible_distribution|lower == 'openbsd' diff --git a/needs_refactoring/kubernetes/ansible_helm/files/helm_clusterrolebinding.yml b/needs_refactoring/kubernetes/ansible_helm/files/helm_clusterrolebinding.yml new file mode 100644 index 0000000..330ed2a --- /dev/null +++ b/needs_refactoring/kubernetes/ansible_helm/files/helm_clusterrolebinding.yml @@ -0,0 +1,12 @@ +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: tiller-clusterrolebinding +subjects: +- kind: ServiceAccount + name: tiller + namespace: kube-system +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: "" diff --git a/needs_refactoring/kubernetes/ansible_helm/tasks/main.yml b/needs_refactoring/kubernetes/ansible_helm/tasks/main.yml new file mode 100644 index 0000000..a6a2a09 --- /dev/null +++ b/needs_refactoring/kubernetes/ansible_helm/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: Ubuntu kubernetes/ansible_helm + import_tasks: ubuntu.yml + when: ansible_distribution|lower == 'ubuntu' diff --git a/needs_refactoring/kubernetes/ansible_helm/tasks/ubuntu.yml b/needs_refactoring/kubernetes/ansible_helm/tasks/ubuntu.yml new file mode 100644 index 0000000..e69de29 diff --git a/needs_refactoring/kubernetes/gitea/files/gitea.yml b/needs_refactoring/kubernetes/gitea/files/gitea.yml new file mode 100644 index 0000000..e517be3 --- /dev/null +++ b/needs_refactoring/kubernetes/gitea/files/gitea.yml @@ -0,0 +1,76 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: gitea +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: git-data-claim + labels: + app: gitea +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gitea-deployment + labels: + app: gitea +spec: + replicas: 1 + selector: + matchLabels: + app: gitea + template: + metadata: + labels: + app: gitea + spec: + containers: + - name: gitea + image: gitea/gitea:latest + imagePullPolicy: "Always" + ports: + - containerPort: 3000 + name: gitea + - containerPort: 22 + name: git-ssh + volumeMounts: + - mountPath: /data + name: git-data + env: + - name: USER_UID + value: "1000" + - name: USER_GID + value: "1000" + - name: LOCAL_ROOT_URL + value: "http://gitea-external.gitea.svc.cluster.local:3000" + volumes: + - name: git-data + persistentVolumeClaim: + claimName: git-data-claim +--- +apiVersion: v1 +kind: Service +metadata: + name: gitea-external +spec: + ports: + - name: gitea + port: 80 + protocol: TCP + targetPort: 3000 + - name: git-ssh + port: 22 + protocol: TCP + targetPort: 22 + selector: + app: gitea + sessionAffinity: None + type: LoadBalancer diff --git a/needs_refactoring/kubernetes/gitea/tasks/main.yml b/needs_refactoring/kubernetes/gitea/tasks/main.yml new file mode 100644 index 0000000..dd25473 --- /dev/null +++ b/needs_refactoring/kubernetes/gitea/tasks/main.yml @@ -0,0 +1,18 @@ +--- +- name: "Kubernetes | Copy gitea yaml files" + copy: + src: "{{ item }}" + dest: "/tmp/{{ item }}" + with_items: + - gitea.yml +- name: "Kubernetes | Deploying gitea: {{ item }}" + shell: "kubectl apply -f /tmp/{{ item }} && sleep 10" + with_items: + - gitea.yml +- name: "Helm | Check if concourse is installed" + command: helm status concourse + register: concourse_installed + ignore_errors: yes +- name: "Helm | Install concourse" + command: helm install --namespace gitea --name concourse stable/concourse + when: concourse_installed.rc != 0 diff --git a/needs_refactoring/kubernetes/hcloud_storage/tasks/main.yml b/needs_refactoring/kubernetes/hcloud_storage/tasks/main.yml new file mode 100644 index 0000000..df9b29c --- /dev/null +++ b/needs_refactoring/kubernetes/hcloud_storage/tasks/main.yml @@ -0,0 +1,18 @@ +--- +- name: Create the custom resources CSINodeInfo and CSIDriver + command: "kubectl apply -f {{ item }}" + loop: + - https://raw.githubusercontent.com/kubernetes/csi-api/master/pkg/crd/manifests/csidriver.yaml + - https://raw.githubusercontent.com/kubernetes/csi-api/master/pkg/crd/manifests/csinodeinfo.yaml +- name: Deploy api secret yml from template + template: + src: api_secret.yml + dest: /root/hcloud_api_secret.yml +- name: Create api secret + command: kubectl apply -f /root/hcloud_api_secret.yml +- name: Delete api secret file + file: + state: absent + path: /root/hcloud_api_secret.yml +- name: Deploy CSI driver + command: kubectl apply -f https://raw.githubusercontent.com/hetznercloud/csi-driver/master/deploy/kubernetes/hcloud-csi.yml diff --git a/needs_refactoring/kubernetes/hcloud_storage/templates/api_secret.yml b/needs_refactoring/kubernetes/hcloud_storage/templates/api_secret.yml new file mode 100644 index 0000000..a8bbb39 --- /dev/null +++ b/needs_refactoring/kubernetes/hcloud_storage/templates/api_secret.yml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + name: hcloud-csi + namespace: kube-system +stringData: + token: {{ hcloud_token }} diff --git a/needs_refactoring/kubernetes/hcloud_storage/vars/main.yml b/needs_refactoring/kubernetes/hcloud_storage/vars/main.yml new file mode 100644 index 0000000..4255bc6 --- /dev/null +++ b/needs_refactoring/kubernetes/hcloud_storage/vars/main.yml @@ -0,0 +1,2 @@ +--- +hcloud_token: "{{ lookup('env','HCLOUD_TOKEN') }}" diff --git a/needs_refactoring/kubernetes/insecure_registry/handlers/main.yml b/needs_refactoring/kubernetes/insecure_registry/handlers/main.yml new file mode 100644 index 0000000..8b03afb --- /dev/null +++ b/needs_refactoring/kubernetes/insecure_registry/handlers/main.yml @@ -0,0 +1,4 @@ +- name: restart_docker + service: + name: docker + state: restarted diff --git a/needs_refactoring/kubernetes/insecure_registry/tasks/main.yml b/needs_refactoring/kubernetes/insecure_registry/tasks/main.yml new file mode 100644 index 0000000..ae05c5c --- /dev/null +++ b/needs_refactoring/kubernetes/insecure_registry/tasks/main.yml @@ -0,0 +1,5 @@ +- name: Deploy daemon.json from template + template: + src: daemon.json + dest: /etc/docker/daemon.json + notify: restart_docker diff --git a/needs_refactoring/kubernetes/insecure_registry/templates/daemon.json b/needs_refactoring/kubernetes/insecure_registry/templates/daemon.json new file mode 100644 index 0000000..cacc137 --- /dev/null +++ b/needs_refactoring/kubernetes/insecure_registry/templates/daemon.json @@ -0,0 +1,3 @@ +{ + "insecure-registries" : {{ insecure_registries }} +} diff --git a/needs_refactoring/kubernetes/insecure_registry/vars/main.yml b/needs_refactoring/kubernetes/insecure_registry/vars/main.yml new file mode 100644 index 0000000..d404c02 --- /dev/null +++ b/needs_refactoring/kubernetes/insecure_registry/vars/main.yml @@ -0,0 +1 @@ +insecure_registries: '["10.254.0.3:5000"]' diff --git a/needs_refactoring/kubernetes/metallb/tasks/main.yml b/needs_refactoring/kubernetes/metallb/tasks/main.yml new file mode 100644 index 0000000..6543667 --- /dev/null +++ b/needs_refactoring/kubernetes/metallb/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- name: install metallb + command: kubectl apply -f https://raw.githubusercontent.com/google/metallb/master/manifests/metallb.yaml +- name: deploy config map from template + template: + src: configmap.yml + dest: /root/metallb-configmap.yml +- name: apply config map + command: kubectl apply -f /root/metallb-configmap.yml diff --git a/needs_refactoring/kubernetes/metallb/templates/configmap.yml b/needs_refactoring/kubernetes/metallb/templates/configmap.yml new file mode 100644 index 0000000..7d656b5 --- /dev/null +++ b/needs_refactoring/kubernetes/metallb/templates/configmap.yml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: metallb-system + name: config +data: + config: | + address-pools: + - name: default + protocol: layer2 + addresses: + - "{{ metallb_range }}" diff --git a/needs_refactoring/kubernetes/metallb/vars/main.yml b/needs_refactoring/kubernetes/metallb/vars/main.yml new file mode 100644 index 0000000..7010307 --- /dev/null +++ b/needs_refactoring/kubernetes/metallb/vars/main.yml @@ -0,0 +1,2 @@ +--- +metallb_range: "10.254.0.100-10.254.0.200" diff --git a/needs_refactoring/kubernetes/openebs/tasks/main.yml b/needs_refactoring/kubernetes/openebs/tasks/main.yml new file mode 100644 index 0000000..4b12ae7 --- /dev/null +++ b/needs_refactoring/kubernetes/openebs/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: Ubuntu kubernetes/openebs + import_tasks: ubuntu.yml + when: ansible_distribution|lower == 'ubuntu' diff --git a/needs_refactoring/kubernetes/openebs/tasks/ubuntu.yml b/needs_refactoring/kubernetes/openebs/tasks/ubuntu.yml new file mode 100644 index 0000000..9ccf84c --- /dev/null +++ b/needs_refactoring/kubernetes/openebs/tasks/ubuntu.yml @@ -0,0 +1,15 @@ +--- +- name: enable and start iscsid + systemd: + state: started + enabled: yes + name: iscsid +- name: check if openebs is installed + command: helm status openebs + register: openebs_installed + ignore_errors: yes +- name: install openebs helm chart + local_action: helm install --namespace openebs --name openebs stable/openebs + when: openebs_installed.rc != 0 +- name: make openebs-hostpath default storageclass + command: "kubectl patch storageclass openebs-hostpath -p '{\"metadata\": {\"annotations\":{\"storageclass.kubernetes.io/is-default-class\":\"true\"}}}'" diff --git a/needs_refactoring/kubernetes/rook/files/cluster.yaml b/needs_refactoring/kubernetes/rook/files/cluster.yaml new file mode 100644 index 0000000..beb58de --- /dev/null +++ b/needs_refactoring/kubernetes/rook/files/cluster.yaml @@ -0,0 +1,265 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: rook-ceph +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: rook-ceph-osd + namespace: rook-ceph +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: rook-ceph-mgr + namespace: rook-ceph +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: rook-ceph-osd + namespace: rook-ceph +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: [ "get", "list", "watch", "create", "update", "delete" ] +--- +# Aspects of ceph-mgr that require access to the system namespace +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: rook-ceph-mgr-system + namespace: rook-ceph +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch +--- +# Aspects of ceph-mgr that operate within the cluster's namespace +kind: Role +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: rook-ceph-mgr + namespace: rook-ceph +rules: +- apiGroups: + - "" + resources: + - pods + - services + verbs: + - get + - list + - watch +- apiGroups: + - batch + resources: + - jobs + verbs: + - get + - list + - watch + - create + - update + - delete +- apiGroups: + - ceph.rook.io + resources: + - "*" + verbs: + - "*" +--- +# Allow the operator to create resources in this cluster's namespace +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: rook-ceph-cluster-mgmt + namespace: rook-ceph +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: rook-ceph-cluster-mgmt +subjects: +- kind: ServiceAccount + name: rook-ceph-system + namespace: rook-ceph-system +--- +# Allow the osd pods in this namespace to work with configmaps +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: rook-ceph-osd + namespace: rook-ceph +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: rook-ceph-osd +subjects: +- kind: ServiceAccount + name: rook-ceph-osd + namespace: rook-ceph +--- +# Allow the ceph mgr to access the cluster-specific resources necessary for the mgr modules +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: rook-ceph-mgr + namespace: rook-ceph +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: rook-ceph-mgr +subjects: +- kind: ServiceAccount + name: rook-ceph-mgr + namespace: rook-ceph +--- +# Allow the ceph mgr to access the rook system resources necessary for the mgr modules +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: rook-ceph-mgr-system + namespace: rook-ceph-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: rook-ceph-mgr-system +subjects: +- kind: ServiceAccount + name: rook-ceph-mgr + namespace: rook-ceph +--- +# Allow the ceph mgr to access cluster-wide resources necessary for the mgr modules +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: rook-ceph-mgr-cluster +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: rook-ceph-mgr-cluster +subjects: +- kind: ServiceAccount + name: rook-ceph-mgr + namespace: rook-ceph +--- +apiVersion: ceph.rook.io/v1 +kind: CephCluster +metadata: + name: rook-ceph + namespace: rook-ceph +spec: + cephVersion: + # The container image used to launch the Ceph daemon pods (mon, mgr, osd, mds, rgw). + # v12 is luminous, v13 is mimic, and v14 is nautilus. + # RECOMMENDATION: In production, use a specific version tag instead of the general v13 flag, which pulls the latest release and could result in different + # versions running within the cluster. See tags available at https://hub.docker.com/r/ceph/ceph/tags/. + image: ceph/ceph:v13 + # Whether to allow unsupported versions of Ceph. Currently only luminous and mimic are supported. + # After nautilus is released, Rook will be updated to support nautilus. + # Do not set to true in production. + allowUnsupported: false + # The path on the host where configuration files will be persisted. Must be specified. + # Important: if you reinstall the cluster, make sure you delete this directory from each host or else the mons will fail to start on the new cluster. + # In Minikube, the '/data' directory is configured to persist across reboots. Use "/data/rook" in Minikube environment. + dataDirHostPath: /var/lib/rook + # set the amount of mons to be started + mon: + count: 3 + allowMultiplePerNode: true + # enable the ceph dashboard for viewing cluster status + dashboard: + enabled: true + # serve the dashboard under a subpath (useful when you are accessing the dashboard via a reverse proxy) + # urlPrefix: /ceph-dashboard + # serve the dashboard at the given port. + # port: 8443 + # serve the dashboard using SSL + # ssl: true + network: + # toggle to use hostNetwork + hostNetwork: false + rbdMirroring: + # The number of daemons that will perform the rbd mirroring. + # rbd mirroring must be configured with "rbd mirror" from the rook toolbox. + workers: 0 + # To control where various services will be scheduled by kubernetes, use the placement configuration sections below. + # The example under 'all' would have all services scheduled on kubernetes nodes labeled with 'role=storage-node' and + # tolerate taints with a key of 'storage-node'. +# placement: +# all: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: role +# operator: In +# values: +# - storage-node +# podAffinity: +# podAntiAffinity: +# tolerations: +# - key: storage-node +# operator: Exists +# The above placement information can also be specified for mon, osd, and mgr components +# mon: +# osd: +# mgr: + resources: +# The requests and limits set here, allow the mgr pod to use half of one CPU core and 1 gigabyte of memory +# mgr: +# limits: +# cpu: "500m" +# memory: "1024Mi" +# requests: +# cpu: "500m" +# memory: "1024Mi" +# The above example requests/limits can also be added to the mon and osd components +# mon: +# osd: + storage: # cluster level storage configuration and selection + useAllNodes: true + useAllDevices: true + deviceFilter: + location: + config: + # The default and recommended storeType is dynamically set to bluestore for devices and filestore for directories. + # Set the storeType explicitly only if it is required not to use the default. + # storeType: bluestore + databaseSizeMB: "1024" # this value can be removed for environments with normal sized disks (100 GB or larger) + journalSizeMB: "1024" # this value can be removed for environments with normal sized disks (20 GB or larger) + osdsPerDevice: "1" # this value can be overridden at the node or device level +# Cluster level list of directories to use for storage. These values will be set for all nodes that have no `directories` set. + directories: + # By default create a osd in the dataDirHostPath directory. This should be removed for + # environments where nodes have disks available for Rook to use. + - path: /var/lib/rook +# Individual nodes and their config can be specified as well, but 'useAllNodes' above must be set to false. Then, only the named +# nodes below will be used as storage resources. Each node's 'name' field should match their 'kubernetes.io/hostname' label. +# nodes: +# - name: "172.17.4.101" +# directories: # specific directories to use for storage can be specified for each node +# - path: "/rook/storage-dir" +# resources: +# limits: +# cpu: "500m" +# memory: "1024Mi" +# requests: +# cpu: "500m" +# memory: "1024Mi" +# - name: "172.17.4.201" +# devices: # specific devices to use for storage can be specified for each node +# - name: "sdb" +# - name: "nvme01" # multiple osds can be created on high performance devices +# config: +# osdsPerDevice: "5" +# config: # configuration can be specified at the node level which overrides the cluster level config +# storeType: filestore +# - name: "172.17.4.301" +# deviceFilter: "^sd." diff --git a/needs_refactoring/kubernetes/rook/files/dashboard-external-https.yaml b/needs_refactoring/kubernetes/rook/files/dashboard-external-https.yaml new file mode 100644 index 0000000..78e2617 --- /dev/null +++ b/needs_refactoring/kubernetes/rook/files/dashboard-external-https.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: rook-ceph-mgr-dashboard-external-https + namespace: rook-ceph + labels: + app: rook-ceph-mgr + rook_cluster: rook-ceph +spec: + ports: + - name: dashboard + port: 8443 + protocol: TCP + targetPort: 8443 + selector: + app: rook-ceph-mgr + rook_cluster: rook-ceph + sessionAffinity: None + type: LoadBalancer diff --git a/needs_refactoring/kubernetes/rook/files/operator.yaml b/needs_refactoring/kubernetes/rook/files/operator.yaml new file mode 100644 index 0000000..3e94931 --- /dev/null +++ b/needs_refactoring/kubernetes/rook/files/operator.yaml @@ -0,0 +1,506 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: rook-ceph-system +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: cephclusters.ceph.rook.io +spec: + group: ceph.rook.io + names: + kind: CephCluster + listKind: CephClusterList + plural: cephclusters + singular: cephcluster + scope: Namespaced + version: v1 + validation: + openAPIV3Schema: + properties: + spec: + properties: + cephVersion: + properties: + allowUnsupported: + type: boolean + image: + type: string + name: + pattern: ^(luminous|mimic|nautilus)$ + type: string + dashboard: + properties: + enabled: + type: boolean + urlPrefix: + type: string + port: + type: integer + dataDirHostPath: + pattern: ^/(\S+) + type: string + mon: + properties: + allowMultiplePerNode: + type: boolean + count: + maximum: 9 + minimum: 1 + type: integer + preferredCount: + maximum: 9 + minimum: 0 + type: integer + required: + - count + network: + properties: + hostNetwork: + type: boolean + storage: + properties: + nodes: + items: {} + type: array + useAllDevices: {} + useAllNodes: + type: boolean + required: + - mon + additionalPrinterColumns: + - name: DataDirHostPath + type: string + description: Directory used on the K8s nodes + JSONPath: .spec.dataDirHostPath + - name: MonCount + type: string + description: Number of MONs + JSONPath: .spec.mon.count + - name: Age + type: date + JSONPath: .metadata.creationTimestamp + - name: State + type: string + description: Current State + JSONPath: .status.state +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: cephfilesystems.ceph.rook.io +spec: + group: ceph.rook.io + names: + kind: CephFilesystem + listKind: CephFilesystemList + plural: cephfilesystems + singular: cephfilesystem + scope: Namespaced + version: v1 + additionalPrinterColumns: + - name: MdsCount + type: string + description: Number of MDSs + JSONPath: .spec.metadataServer.activeCount + - name: Age + type: date + JSONPath: .metadata.creationTimestamp +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: cephnfses.ceph.rook.io +spec: + group: ceph.rook.io + names: + kind: CephNFS + listKind: CephNFSList + plural: cephnfses + singular: cephnfs + shortNames: + - nfs + scope: Namespaced + version: v1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: cephobjectstores.ceph.rook.io +spec: + group: ceph.rook.io + names: + kind: CephObjectStore + listKind: CephObjectStoreList + plural: cephobjectstores + singular: cephobjectstore + scope: Namespaced + version: v1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: cephobjectstoreusers.ceph.rook.io +spec: + group: ceph.rook.io + names: + kind: CephObjectStoreUser + listKind: CephObjectStoreUserList + plural: cephobjectstoreusers + singular: cephobjectstoreuser + scope: Namespaced + version: v1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: cephblockpools.ceph.rook.io +spec: + group: ceph.rook.io + names: + kind: CephBlockPool + listKind: CephBlockPoolList + plural: cephblockpools + singular: cephblockpool + scope: Namespaced + version: v1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: volumes.rook.io +spec: + group: rook.io + names: + kind: Volume + listKind: VolumeList + plural: volumes + singular: volume + shortNames: + - rv + scope: Namespaced + version: v1alpha2 +--- +# The cluster role for managing all the cluster-specific resources in a namespace +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: rook-ceph-cluster-mgmt + labels: + operator: rook + storage-backend: ceph +rules: +- apiGroups: + - "" + resources: + - secrets + - pods + - pods/log + - services + - configmaps + verbs: + - get + - list + - watch + - patch + - create + - update + - delete +- apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + verbs: + - get + - list + - watch + - create + - update + - delete +--- +# The role for the operator to manage resources in the system namespace +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: Role +metadata: + name: rook-ceph-system + namespace: rook-ceph-system + labels: + operator: rook + storage-backend: ceph +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: + - get + - list + - watch + - patch + - create + - update + - delete +- apiGroups: + - apps + resources: + - daemonsets + verbs: + - get + - list + - watch + - create + - update + - delete +--- +# The cluster role for managing the Rook CRDs +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: rook-ceph-global + labels: + operator: rook + storage-backend: ceph +rules: +- apiGroups: + - "" + resources: + # Pod access is needed for fencing + - pods + # Node access is needed for determining nodes where mons should run + - nodes + - nodes/proxy + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - events + # PVs and PVCs are managed by the Rook provisioner + - persistentvolumes + - persistentvolumeclaims + - endpoints + verbs: + - get + - list + - watch + - patch + - create + - update + - delete +- apiGroups: + - storage.k8s.io + resources: + - storageclasses + verbs: + - get + - list + - watch +- apiGroups: + - batch + resources: + - jobs + verbs: + - get + - list + - watch + - create + - update + - delete +- apiGroups: + - ceph.rook.io + resources: + - "*" + verbs: + - "*" +- apiGroups: + - rook.io + resources: + - "*" + verbs: + - "*" +--- +# Aspects of ceph-mgr that require cluster-wide access +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: rook-ceph-mgr-cluster + labels: + operator: rook + storage-backend: ceph +rules: +- apiGroups: + - "" + resources: + - configmaps + - nodes + - nodes/proxy + verbs: + - get + - list + - watch +--- +# The rook system service account used by the operator, agent, and discovery pods +apiVersion: v1 +kind: ServiceAccount +metadata: + name: rook-ceph-system + namespace: rook-ceph-system + labels: + operator: rook + storage-backend: ceph +--- +# Grant the operator, agent, and discovery agents access to resources in the rook-ceph-system namespace +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: rook-ceph-system + namespace: rook-ceph-system + labels: + operator: rook + storage-backend: ceph +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: rook-ceph-system +subjects: +- kind: ServiceAccount + name: rook-ceph-system + namespace: rook-ceph-system +--- +# Grant the rook system daemons cluster-wide access to manage the Rook CRDs, PVCs, and storage classes +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: rook-ceph-global + namespace: rook-ceph-system + labels: + operator: rook + storage-backend: ceph +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: rook-ceph-global +subjects: +- kind: ServiceAccount + name: rook-ceph-system + namespace: rook-ceph-system +--- +# The deployment for the rook operator +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: rook-ceph-operator + namespace: rook-ceph-system + labels: + operator: rook + storage-backend: ceph +spec: + replicas: 1 + template: + metadata: + labels: + app: rook-ceph-operator + spec: + serviceAccountName: rook-ceph-system + containers: + - name: rook-ceph-operator + image: rook/ceph:master + args: ["ceph", "operator"] + volumeMounts: + - mountPath: /var/lib/rook + name: rook-config + - mountPath: /etc/ceph + name: default-config-dir + env: + # To disable RBAC, uncomment the following: + # - name: RBAC_ENABLED + # value: "false" + # Rook Agent toleration. Will tolerate all taints with all keys. + # Choose between NoSchedule, PreferNoSchedule and NoExecute: + # - name: AGENT_TOLERATION + # value: "NoSchedule" + # (Optional) Rook Agent toleration key. Set this to the key of the taint you want to tolerate + # - name: AGENT_TOLERATION_KEY + # value: "" + # (Optional) Rook Agent mount security mode. Can by `Any` or `Restricted`. + # `Any` uses Ceph admin credentials by default/fallback. + # For using `Restricted` you must have a Ceph secret in each namespace storage should be consumed from and + # set `mountUser` to the Ceph user, `mountSecret` to the Kubernetes secret name. + # to the namespace in which the `mountSecret` Kubernetes secret namespace. + # - name: AGENT_MOUNT_SECURITY_MODE + # value: "Any" + # Set the path where the Rook agent can find the flex volumes + # - name: FLEXVOLUME_DIR_PATH + # value: "" + # Set the path where kernel modules can be found + # - name: LIB_MODULES_DIR_PATH + # value: "" + # Mount any extra directories into the agent container + # - name: AGENT_MOUNTS + # value: "somemount=/host/path:/container/path,someothermount=/host/path2:/container/path2" + # Rook Discover toleration. Will tolerate all taints with all keys. + # Choose between NoSchedule, PreferNoSchedule and NoExecute: + # - name: DISCOVER_TOLERATION + # value: "NoSchedule" + # (Optional) Rook Discover toleration key. Set this to the key of the taint you want to tolerate + # - name: DISCOVER_TOLERATION_KEY + # value: "" + # Allow rook to create multiple file systems. Note: This is considered + # an experimental feature in Ceph as described at + # http://docs.ceph.com/docs/master/cephfs/experimental-features/#multiple-filesystems-within-a-ceph-cluster + # which might cause mons to crash as seen in https://github.com/rook/rook/issues/1027 + - name: ROOK_ALLOW_MULTIPLE_FILESYSTEMS + value: "false" + # The logging level for the operator: INFO | DEBUG + - name: ROOK_LOG_LEVEL + value: "INFO" + # The interval to check if every mon is in the quorum. + - name: ROOK_MON_HEALTHCHECK_INTERVAL + value: "45s" + # The duration to wait before trying to failover or remove/replace the + # current mon with a new mon (useful for compensating flapping network). + - name: ROOK_MON_OUT_TIMEOUT + value: "600s" + # The duration between discovering devices in the rook-discover daemonset. + - name: ROOK_DISCOVER_DEVICES_INTERVAL + value: "60m" + # Whether to start pods as privileged that mount a host path, which includes the Ceph mon and osd pods. + # This is necessary to workaround the anyuid issues when running on OpenShift. + # For more details see https://github.com/rook/rook/issues/1314#issuecomment-355799641 + - name: ROOK_HOSTPATH_REQUIRES_PRIVILEGED + value: "false" + # In some situations SELinux relabelling breaks (times out) on large filesystems, and doesn't work with cephfs ReadWriteMany volumes (last relabel wins). + # Disable it here if you have similar issues. + # For more details see https://github.com/rook/rook/issues/2417 + - name: ROOK_ENABLE_SELINUX_RELABELING + value: "true" + # In large volumes it will take some time to chown all the files. Disable it here if you have performance issues. + # For more details see https://github.com/rook/rook/issues/2254 + - name: ROOK_ENABLE_FSGROUP + value: "true" + # The name of the node to pass with the downward API + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + # The pod name to pass with the downward API + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + # The pod namespace to pass with the downward API + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + volumes: + - name: rook-config + emptyDir: {} + - name: default-config-dir + emptyDir: {} diff --git a/needs_refactoring/kubernetes/rook/files/storageclass.yaml b/needs_refactoring/kubernetes/rook/files/storageclass.yaml new file mode 100644 index 0000000..1998730 --- /dev/null +++ b/needs_refactoring/kubernetes/rook/files/storageclass.yaml @@ -0,0 +1,29 @@ +apiVersion: ceph.rook.io/v1 +kind: CephBlockPool +metadata: + name: replicapool + namespace: rook-ceph +spec: + replicated: + size: 1 +--- +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: rook-ceph-block + annotations: + storageclass.kubernetes.io/is-default-class: "true" +provisioner: ceph.rook.io/block +parameters: + blockPool: replicapool + # Specify the namespace of the rook cluster from which to create volumes. + # If not specified, it will use `rook` as the default namespace of the cluster. + # This is also the namespace where the cluster will be + clusterNamespace: rook-ceph + # Specify the filesystem type of the volume. If not specified, it will use `ext4`. + fstype: xfs + # (Optional) Specify an existing Ceph user that will be used for mounting storage with this StorageClass. + #mountUser: user1 + # (Optional) Specify an existing Kubernetes secret name containing just one key holding the Ceph user secret. + # The secret must exist in each namespace(s) where the storage will be consumed. + #mountSecret: ceph-user1-secret diff --git a/needs_refactoring/kubernetes/rook/tasks/main.yml b/needs_refactoring/kubernetes/rook/tasks/main.yml new file mode 100644 index 0000000..3139b9a --- /dev/null +++ b/needs_refactoring/kubernetes/rook/tasks/main.yml @@ -0,0 +1,17 @@ +--- +- name: "Kubernetes | Copy yaml files" + copy: + src: "{{ item }}" + dest: "/tmp/{{ item }}" + with_items: + - operator.yaml + - cluster.yaml + - dashboard-external-https.yaml + - storageclass.yaml +- name: "Kubernetes | Deploying rook: {{ item }}" + shell: "kubectl create -f /tmp/{{ item }} && sleep 10" + with_items: + - operator.yaml + - cluster.yaml + - dashboard-external-https.yaml + - storageclass.yaml diff --git a/needs_refactoring/natgw/handlers/main.yml b/needs_refactoring/natgw/handlers/main.yml new file mode 100644 index 0000000..36d582b --- /dev/null +++ b/needs_refactoring/natgw/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: reload pf for real + shell: pfctl -f /etc/pf.conf +- name: reload pf + shell: pfctl -nf /etc/pf.conf + notify: reload pf for real diff --git a/needs_refactoring/natgw/tasks/common.yml b/needs_refactoring/natgw/tasks/common.yml new file mode 100644 index 0000000..37758be --- /dev/null +++ b/needs_refactoring/natgw/tasks/common.yml @@ -0,0 +1,21 @@ +--- +- name: create admin users + user: + name: '{{ item }}' + groups: wheel + state: present + with_items: "{{ admin_users }}" + when: ansible_distribution|lower == 'openbsd' +- name: deploy authorized_keys + authorized_key: + user: "{{ item }}" + key: "{{ lookup('file', item + '.pub') }}" + state: present + with_items: "{{ admin_users }}" +- name: deploy vimrc + copy: + src: vimrc + dest: /home/mw/.vimrc + owner: mw + group: mw + mode: 0644 diff --git a/needs_refactoring/natgw/tasks/main.yml b/needs_refactoring/natgw/tasks/main.yml new file mode 100644 index 0000000..6401dd8 --- /dev/null +++ b/needs_refactoring/natgw/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: OpenBSD NAT Gateway + import_tasks: openbsd.yml + when: ansible_distribution|lower == 'openbsd' diff --git a/needs_refactoring/natgw/tasks/openbsd.yml b/needs_refactoring/natgw/tasks/openbsd.yml new file mode 100644 index 0000000..5687418 --- /dev/null +++ b/needs_refactoring/natgw/tasks/openbsd.yml @@ -0,0 +1,21 @@ +--- +- name: ipv4 forwarding + sysctl: + name: net.inet.ip.forwarding + value: 1 + state: present + reload: yes +- name: ipv6 forwarding + sysctl: + name: net.inet6.ip6.forwarding + value: 1 + state: present + reload: yes +- name: pf rules + lineinfile: + path: /etc/anchors/ansible + line: "{{ item }}" + with_items: + - "match out on egress from !egress nat-to egress:0" + - "pass out on egress from egress:0" + notify: reload pf diff --git a/needs_refactoring/webserver/handlers/main.yml b/needs_refactoring/webserver/handlers/main.yml new file mode 100644 index 0000000..434d529 --- /dev/null +++ b/needs_refactoring/webserver/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: reload httpd + service: + name: httpd + state: reloaded diff --git a/needs_refactoring/webserver/tasks/main.yml b/needs_refactoring/webserver/tasks/main.yml new file mode 100644 index 0000000..0d8973b --- /dev/null +++ b/needs_refactoring/webserver/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: OpenBSD httpd + import_tasks: openbsd.yml + when: ansible_distribution|lower == 'openbsd' diff --git a/needs_refactoring/webserver/tasks/openbsd.yml b/needs_refactoring/webserver/tasks/openbsd.yml new file mode 100644 index 0000000..e6e5b28 --- /dev/null +++ b/needs_refactoring/webserver/tasks/openbsd.yml @@ -0,0 +1,41 @@ +--- +- name: acme-client.conf + template: + src: acme-client.conf + dest: /etc/acme-client.conf + owner: root + group: wheel + mode: 0640 + when: tls +- name: tls key and certificate + stat: + path: "{{ item }}" + with_items: + - "{{ tls_certificate }}" + - "{{ tls_key }}" + register: st_tls +- name: httpd.conf + template: + src: httpd.conf + dest: /etc/httpd.conf + owner: root + group: wheel + mode: 0640 + notify: reload httpd +- name: httpd enabled and started + service: + name: httpd + state: started + enabled: true +- name: run acme-client + command: "acme-client -A -D -f /etc/acme-client.conf {{ fqdn }}" + when: tls + notify: reload httpd +- name: acme-client cronjob + cron: + name: "run acme-client" + minute: 0 + hour: 3 + user: root + job: "acme-client -A -D -f /etc/acme-client.conf {{ fqdn }}" + when: tls diff --git a/needs_refactoring/webserver/templates/acme-client.conf b/needs_refactoring/webserver/templates/acme-client.conf new file mode 100644 index 0000000..5e08e73 --- /dev/null +++ b/needs_refactoring/webserver/templates/acme-client.conf @@ -0,0 +1,23 @@ +# +# $OpenBSD: acme-client.conf,v 1.7 2018/04/13 08:24:38 ajacoutot Exp $ +# +authority letsencrypt { + api url "https://acme-v01.api.letsencrypt.org/directory" + account key "/etc/acme/letsencrypt-privkey.pem" +} + +authority letsencrypt-staging { + api url "https://acme-staging.api.letsencrypt.org/directory" + account key "/etc/acme/letsencrypt-staging-privkey.pem" +} + +domain "{{ fqdn }}" { + domain key "/etc/ssl/private/{{ fqdn }}.key" + domain certificate "/etc/ssl/{{ fqdn }}.crt" + domain full chain certificate "/etc/ssl/{{ fqdn }}.fullchain.pem" + {% if letsencrypt_staging %} + sign with letsencrypt-staging + {% else %} + sign with letsencrypt + {% endif %} +} diff --git a/needs_refactoring/webserver/templates/httpd.conf b/needs_refactoring/webserver/templates/httpd.conf new file mode 100644 index 0000000..0b5e572 --- /dev/null +++ b/needs_refactoring/webserver/templates/httpd.conf @@ -0,0 +1,36 @@ +# $OpenBSD: httpd.conf,v 1.20 2018/06/13 15:08:24 reyk Exp $ + +server "{{ fqdn }}" { + listen on * port 80 + location "/.well-known/acme-challenge/*" { + root "/acme" + request strip 2 + } + {% if not tls %} + location "/pub/*" { + directory auto index + } + {% endif %} + {% if tls %} + location * { + block return 302 "https://$HTTP_HOST$REQUEST_URI" + } + {% endif %} +} + +{% if st_tls.results.0.stat.exists and st_tls.results.1.stat.exists and tls %} +server "{{ fqdn }}" { + listen on * tls port 443 + tls { + certificate "{{ tls_certificate }}" + key "{{ tls_key }}" + } + location "/pub/*" { + directory auto index + } + location "/.well-known/acme-challenge/*" { + root "/acme" + request strip 2 + } +} +{% endif %} diff --git a/needs_refactoring/webserver/vars/main.yml b/needs_refactoring/webserver/vars/main.yml new file mode 100644 index 0000000..c1c1795 --- /dev/null +++ b/needs_refactoring/webserver/vars/main.yml @@ -0,0 +1,7 @@ +--- +fqdn: "{{ ansible_fqdn }}" +webroot: "/var/www/htdocs" +tls: False +tls_certificate: "/etc/ssl/{{ fqdn }}.fullchain.pem" +tls_key: "/etc/ssl/private/{{ fqdn }}.key" +letsencrypt_staging: True diff --git a/nginx/defaults/main.yml b/nginx/defaults/main.yml new file mode 100644 index 0000000..f88cf6d --- /dev/null +++ b/nginx/defaults/main.yml @@ -0,0 +1,4 @@ +--- +nginx_required_packages: + ubuntu: + - nginx-core diff --git a/nginx/tasks/main.yml b/nginx/tasks/main.yml new file mode 100644 index 0000000..7556574 --- /dev/null +++ b/nginx/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- name: install required packages + package: + name: "{{ item }}" + state: present + loop: "{{ nginx_required_packages[ansible_distribution] | lower }}" diff --git a/openbsd_install_from_rescue/defaults/main.yml b/openbsd_install_from_rescue/defaults/main.yml new file mode 100644 index 0000000..2117c93 --- /dev/null +++ b/openbsd_install_from_rescue/defaults/main.yml @@ -0,0 +1,2 @@ +openbsd_autoinstall_miniroot: autoinstall67.fs.gz +openbsd_autoinstall_rootdisk: /dev/sda diff --git a/openbsd_install_from_rescue/tasks/main.yml b/openbsd_install_from_rescue/tasks/main.yml new file mode 100644 index 0000000..f4ea993 --- /dev/null +++ b/openbsd_install_from_rescue/tasks/main.yml @@ -0,0 +1,5 @@ +- name: run openbsd install tasks + include_tasks: openbsd_install.yml + vars: + ansible_become: yes + when: ansible_distribution != "OpenBSD" diff --git a/openbsd_install_from_rescue/tasks/openbsd_install.yml b/openbsd_install_from_rescue/tasks/openbsd_install.yml new file mode 100644 index 0000000..e181690 --- /dev/null +++ b/openbsd_install_from_rescue/tasks/openbsd_install.yml @@ -0,0 +1,26 @@ +- name: copy openbsd miniroot to server + copy: + src: "{{ openbsd_autoinstall_miniroot }}" + dest: "/tmp/miniroot.fs.gz" + +- name: write miniroot to disk + shell: "gunzip -c /tmp/miniroot.fs.gz | dd of={{ openbsd_autoinstall_rootdisk }} bs=10M" + +- name: clear facts and notify reboot handler + meta: clear_facts + + +- name: set python interpreter + set_fact: + ansible_python_interpreter: /usr/local/bin/python3 + +- name: reboot + raw: reboot + + +- name: wait_for autoinstall to finish + wait_for_connection: + delay: 10 + +- name: gather facts + setup: diff --git a/openbsd_mirror/defaults/main.yml b/openbsd_mirror/defaults/main.yml new file mode 100644 index 0000000..60c38c3 --- /dev/null +++ b/openbsd_mirror/defaults/main.yml @@ -0,0 +1,6 @@ +--- +mirror: "ftp.hostserver.de" +mirror_root: "/var/www/htdocs/pub" +mirror_targets: + - "OpenBSD/6.9/amd64" + - "OpenBSD/snapshots/amd64" diff --git a/openbsd_mirror/handlers/main.yml b/openbsd_mirror/handlers/main.yml new file mode 100644 index 0000000..027c41d --- /dev/null +++ b/openbsd_mirror/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: reload httpd + command: rcctl reload httpd +- name: restart httpd + command: rcctl restart httpd diff --git a/openbsd_mirror/tasks/main.yml b/openbsd_mirror/tasks/main.yml new file mode 100644 index 0000000..0ee9350 --- /dev/null +++ b/openbsd_mirror/tasks/main.yml @@ -0,0 +1,26 @@ +--- +- name: mirror directories + become: yes + file: + path: "{{ mirror_root }}/{{ item }}" + owner: www + group: daemon + state: directory + recurse: yes + with_items: + - "{{ mirror_targets }}" +- name: rsync + become: yes + community.general.openbsd_pkg: + name: rsync-- + state: present + snapshot: "{{ force_openbsd_snapshot | default(false) }}" +- name: synchronize mirror + become: yes + synchronize: + mode: pull + src: "rsync://{{ mirror }}/{{ item }}/" + dest: "{{ mirror_root }}/{{ item }}/" + delegate_to: "{{ inventory_hostname }}" + with_items: + - "{{ mirror_targets }}" diff --git a/sysupgrade/defaults/main.yml b/sysupgrade/defaults/main.yml new file mode 100644 index 0000000..501f8a0 --- /dev/null +++ b/sysupgrade/defaults/main.yml @@ -0,0 +1 @@ +sysupgrade_openbsd_args: "" diff --git a/sysupgrade/tasks/main.yml b/sysupgrade/tasks/main.yml new file mode 100644 index 0000000..2ca02a6 --- /dev/null +++ b/sysupgrade/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- name: run openbsd specific include taks + include_tasks: openbsd.yml + when: ansible_distribution == 'OpenBSD' + tags: + - sysupgrade diff --git a/sysupgrade/tasks/openbsd.yml b/sysupgrade/tasks/openbsd.yml new file mode 100644 index 0000000..eb01311 --- /dev/null +++ b/sysupgrade/tasks/openbsd.yml @@ -0,0 +1,14 @@ +--- + +- name: download install sets for sysupgrade + become: yes + shell: "sysupgrade -n {{ sysupgrade_openbsd_args }}" + register: sysupgrade_task + changed_when: "'Will upgrade on next reboot' in sysupgrade_task.stdout" + +- name: wait for upgrade to finish + become: yes + reboot: + reboot_timeout: 900 + when: sysupgrade_task.changed + diff --git a/webserver/defaults/main.yml b/webserver/defaults/main.yml new file mode 100644 index 0000000..a30e78a --- /dev/null +++ b/webserver/defaults/main.yml @@ -0,0 +1,13 @@ +--- +webserver_fqdn: "{{ ansible_fqdn }}" +webserver_tls: False +webserver_letsencrypt: False +webserver_tls_certificate: "/etc/ssl/{{ webserver_fqdn }}.fullchain.pem" +webserver_tls_key: "/etc/ssl/private/{{ webserver_fqdn }}.key" +webserver_letsencrypt_staging: True +webserver_tls_alternative_names: + - "another.domain.tld" +webserver_htpasswd_users: + - name: username + password: XXXXXX + state: present diff --git a/webserver/handlers/main.yml b/webserver/handlers/main.yml new file mode 100644 index 0000000..2ebd22f --- /dev/null +++ b/webserver/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: reload httpd + become: yes + service: + name: httpd + state: reloaded diff --git a/webserver/tasks/common.yml b/webserver/tasks/common.yml new file mode 100644 index 0000000..7acf10c --- /dev/null +++ b/webserver/tasks/common.yml @@ -0,0 +1,52 @@ +- name: install required packages + package: + name: "{{ package }}" + state: present + loop: "{{ webserver_packages[ansible_distribution|lower] }}" + loop_control: + loop_var: package + when: ansible_distribution|lower != 'openbsd' + +- name: install required packages + community.general.openbsd_pkg: + name: "{{ package }}" + state: present + snapshot: "{{ force_openbsd_snapshot|default(false) }}" + loop: "{{ webserver_packages[ansible_distribution|lower] }}" + loop_control: + loop_var: package + when: ansible_distribution|lower == 'openbsd' + +- name: create directories + file: + name: "{{ dir.path }}" + state: directory + owner: "{{ dir.owner }}" + loop: "{{ webserver_directories[ansible_distribution|lower] }}" + loop_control: + loop_var: dir + +- name: setup htpasswd file + htpasswd: + name: "{{ user.name }}" + state: "{{ user.state|default('present') }}" + password: "{{ user.password }}" + path: "{{ webserver_htpasswd_file[ansible_distribution|lower].path }}" + owner: "{{ webserver_htpasswd_file[ansible_distribution|lower].owner }}" + group: "{{ webserver_htpasswd_file[ansible_distribution|lower].group }}" + mode: "{{ webserver_htpasswd_file[ansible_distribution|lower].mode }}" + crypt_scheme: "{{ webserver_htpasswd_file[ansible_distribution|lower].crypt_scheme }}" + loop: "{{ webserver_htpasswd_users }}" + loop_control: + loop_var: user + +- name: "ensure {{ cfg.line }} is in {{ cfg.path }}" + lineinfile: + path: "{{ cfg.path }}" + line: "{{ cfg.line }}" + regexp: "{{ cfg.regexp }}" + create: yes + loop: "{{ webserver_config_insertions[ ansible_distribution|lower ] }}" + loop_control: + loop_var: cfg + notify: reload httpd diff --git a/webserver/tasks/main.yml b/webserver/tasks/main.yml new file mode 100644 index 0000000..91c1a80 --- /dev/null +++ b/webserver/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- name: Common webserver tasks + include_tasks: common.yml + vars: + ansible_become: yes + +- name: OpenBSD httpd + include_tasks: openbsd.yml + when: ansible_distribution|lower == 'openbsd' + vars: + ansible_become: yes + diff --git a/webserver/tasks/openbsd.yml b/webserver/tasks/openbsd.yml new file mode 100644 index 0000000..8641c61 --- /dev/null +++ b/webserver/tasks/openbsd.yml @@ -0,0 +1,44 @@ +--- +- name: acme-client.conf + template: + src: acme-client.conf + dest: /etc/acme-client.conf + owner: root + group: wheel + mode: 0640 + when: webserver_tls +- name: tls key and certificate + stat: + path: "{{ item }}" + with_items: + - "{{ webserver_tls_certificate }}" + - "{{ webserver_tls_key }}" + register: st_tls +- name: httpd.conf + template: + src: httpd.conf + dest: /etc/httpd.conf.default + owner: root + group: wheel + mode: 0640 + notify: reload httpd +- name: httpd enabled and started + service: + name: httpd + state: started + enabled: true +- name: run acme-client + command: "acme-client -f /etc/acme-client.conf {{ webserver_fqdn }}" + when: webserver_tls and webserver_letsencrypt + notify: reload httpd + register: cert_update + failed_when: cert_update.rc == 1 + changed_when: cert_update.rc == 0 +- name: acme-client cronjob + cron: + name: "run acme-client" + minute: "0" + hour: "3" + user: root + job: "acme-client -f /etc/acme-client.conf {{ webserver_fqdn }}" + when: webserver_tls and webserver_letsencrypt diff --git a/webserver/templates/acme-client.conf b/webserver/templates/acme-client.conf new file mode 100644 index 0000000..cc18f1f --- /dev/null +++ b/webserver/templates/acme-client.conf @@ -0,0 +1,26 @@ +# +# $OpenBSD: acme-client.conf,v 1.7 2018/04/13 08:24:38 ajacoutot Exp $ +# +authority letsencrypt { + api url "https://acme-v02.api.letsencrypt.org/directory" + account key "/etc/acme/letsencrypt-privkey.pem" +} + +authority letsencrypt-staging { + api url "https://acme-v02.api.letsencrypt.org/directory" + account key "/etc/acme/letsencrypt-staging-privkey.pem" +} + +domain "{{ webserver_fqdn }}" { + {% if webserver_tls_alternative_names is defined and webserver_tls_alternative_names|length > 0 %} + alternative names { {{ webserver_tls_alternative_names|join(' ') }} } + {% endif %} + domain key "/etc/ssl/private/{{ webserver_fqdn }}.key" + domain certificate "/etc/ssl/{{ webserver_fqdn }}.crt" + domain full chain certificate "/etc/ssl/{{ webserver_fqdn }}.fullchain.pem" + {% if webserver_letsencrypt_staging %} + sign with letsencrypt-staging + {% else %} + sign with letsencrypt + {% endif %} +} diff --git a/webserver/templates/httpd.conf b/webserver/templates/httpd.conf new file mode 100644 index 0000000..fa5260e --- /dev/null +++ b/webserver/templates/httpd.conf @@ -0,0 +1,40 @@ +# $OpenBSD: httpd.conf,v 1.20 2018/06/13 15:08:24 reyk Exp $ + +server "default" { + listen on * port 80 + location "/.well-known/acme-challenge/*" { + root "/acme" + request strip 2 + } + {% if not webserver_tls %} + location "/pub/*" { + directory auto index + } + {% endif %} + {% if webserver_tls %} + location * { + block return 302 "https://$HTTP_HOST$REQUEST_URI" + } + {% endif %} +} + +{% if st_tls.results.0.stat.exists and st_tls.results.1.stat.exists and webserver_tls %} +server "default" { + listen on * tls port 443 + tls { + certificate "{{ webserver_tls_certificate }}" + key "{{ webserver_tls_key }}" + } + location "/pub/*" { + directory auto index + } + location "/restricted/*" { + directory auto index + authenticate "{{ webserver_fqdn }}" with "{{ webserver_htpasswd_file[ansible_distribution|lower].chroot_path }}" + } + location "/.well-known/acme-challenge/*" { + root "/acme" + request strip 2 + } +} +{% endif %} diff --git a/webserver/vars/main.yml b/webserver/vars/main.yml new file mode 100644 index 0000000..823e705 --- /dev/null +++ b/webserver/vars/main.yml @@ -0,0 +1,25 @@ +webserver_htpasswd_file: + openbsd: + path: /var/www/htpasswd + chroot_path: /htpasswd + owner: www + group: www + mode: "0400" + crypt_scheme: "bcrypt" + +webserver_packages: + openbsd: + - py3-passlib + +webserver_directories: + openbsd: + - path: /var/www/htdocs/pub + owner: www + - path: /var/www/htdocs/restricted + owner: www + +webserver_config_insertions: + openbsd: + - path: /etc/httpd.conf + line: 'include "/etc/httpd.conf.default"' + regexp: '^.*include.*"/etc/httpd.conf.default".*$' diff --git a/wireguard/defaults/main.yaml b/wireguard/defaults/main.yaml new file mode 100644 index 0000000..79d308c --- /dev/null +++ b/wireguard/defaults/main.yaml @@ -0,0 +1,12 @@ +--- +wg_if: "wg0" +wg_desc: "Wireguard VPN (ansible managed)" +wg_port: 43168 +wg_net : "10.253.254.1/24" +wg_peers: + - pubkey: "XXXX" + allowed_nets: + - "10.253.254.12/32" + - pubkey: "XXXX" + allowed_nets: + - "10.253.254.13/32" diff --git a/wireguard/handlers/main.yaml b/wireguard/handlers/main.yaml new file mode 100644 index 0000000..3a11d80 --- /dev/null +++ b/wireguard/handlers/main.yaml @@ -0,0 +1,14 @@ +--- +- name: wg-reload + systemd: + name: systemd-networkd + state: restarted + daemon_reload: yes + become: yes +- name: iptables-save-ubuntu + command: netfilter-persistent save + become: yes + +- name: openbsd-wg-reload + shell: "sh /etc/netstart {{ wg_if }}" + become: yes diff --git a/wireguard/tasks/arch.yml b/wireguard/tasks/arch.yml new file mode 100644 index 0000000..0cd355d --- /dev/null +++ b/wireguard/tasks/arch.yml @@ -0,0 +1,8 @@ +--- +- name: install packages + package: + name: "{{ item }}" + state: present + with_items: + - wireguard-tools + diff --git a/wireguard/tasks/main.yml b/wireguard/tasks/main.yml new file mode 100644 index 0000000..b623a6c --- /dev/null +++ b/wireguard/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- name: OpenBSD wireguard setup + include_tasks: openbsd.yml + when: ansible_distribution|lower == 'openbsd' + vars: + ansible_become: yes + +- name: systemd based wireguard setup + include_tasks: systemd_linux.yml + when: ansible_service_mgr|lower == 'systemd' + vars: + ansible_become: yes diff --git a/wireguard/tasks/openbsd.yml b/wireguard/tasks/openbsd.yml new file mode 100644 index 0000000..f22d996 --- /dev/null +++ b/wireguard/tasks/openbsd.yml @@ -0,0 +1,31 @@ +--- +- name: check if wireguard key exists + stat: + path: /etc/wireguard/key + register: key_exists + +- name: ensure wireguard directory exists + file: + path: /etc/wireguard + state: directory + mode: 0700 + +- name: create key + shell: openssl rand -base64 32 > /etc/wireguard/key + when: key_exists.stat.exists == False + +- name: ensure key has the right permissions + file: + path: /etc/wireguard/key + mode: '0600' + +- name: slurp private key + slurp: + src: /etc/wireguard/key + register: wg_key + +- name: write wireguard interface config + template: + src: hostname.wg0.j2 + dest: "/etc/hostname.{{ wg_if }}" + notify: openbsd-wg-reload diff --git a/wireguard/tasks/systemd_linux.yml b/wireguard/tasks/systemd_linux.yml new file mode 100644 index 0000000..b45c7b2 --- /dev/null +++ b/wireguard/tasks/systemd_linux.yml @@ -0,0 +1,45 @@ +--- +- name: arch linux wireguard setup + import_tasks: arch.yml + when: ansible_distribution|lower == 'archlinux' + +- name: ubuntu linux wireguard setup + import_tasks: ubuntu.yml + when: ansible_distribution|lower == 'ubuntu' + +- name: check if key exists + stat: + path: /etc/wireguard/key + register: key_exists + +- name: create keys + shell: wg genkey | tee /etc/wireguard/key | wg pubkey > /etc/wireguard/pubkey + when: key_exists.stat.exists == False + +- name: read private key into variable + shell: cat /etc/wireguard/key + register: wg_private_key + +- name: deploy systemd wg interface config + template: + src: 30-wg0.netdev.jinja2 + dest: /etc/systemd/network/30-wg0.netdev + owner: systemd-network + mode: 0600 + notify: wg-reload + +- name: deploy systemd network configuration + template: + src: 30-wg0.network.jinja2 + dest: /etc/systemd/network/30-wg0.network + owner: systemd-network + mode: 0600 + notify: wg-reload + +- name: get pubkey + shell: cat /etc/wireguard/pubkey + register: wg_pubkey + +- name: print pubkey + debug: + var: wg_pubkey.stdout_lines diff --git a/wireguard/tasks/ubuntu.yml b/wireguard/tasks/ubuntu.yml new file mode 100644 index 0000000..2486ca1 --- /dev/null +++ b/wireguard/tasks/ubuntu.yml @@ -0,0 +1,11 @@ +--- +- name: add wireguard ppa + apt_repository: + repo: ppa:wireguard/wireguard +- name: install linux headers + shell: apt-get install -y linux-headers-$(uname -r) +- name: install wireguard + apt: + name: [ "wireguard-dkms", "wireguard-tools" ] + state: present + register: wg_installed diff --git a/wireguard/templates/30-wg0.netdev.jinja2 b/wireguard/templates/30-wg0.netdev.jinja2 new file mode 100644 index 0000000..2119310 --- /dev/null +++ b/wireguard/templates/30-wg0.netdev.jinja2 @@ -0,0 +1,21 @@ +[NetDev] +Name = {{ wg_if }} +Kind = wireguard +Description = {{ wg_desc }} + +[WireGuard] +PrivateKey = {{ wg_private_key.stdout_lines[0] }} +ListenPort = {{ wg_port }} + +{% if wg_peers is defined %} +{% for wg_peer in wg_peers %} +[WireGuardPeer] +PublicKey = {{ wg_peer.pubkey }} +{% for net in wg_peer.allowed_nets %} +AllowedIPs = {{ net }} +{% endfor %} +{% if wg_peer.ip is defined %} +Endpoint = {{ wg_peer.ip }}:{{ wg_peer.port }} +{% endif %} +{% endfor %} +{% endif %} diff --git a/wireguard/templates/30-wg0.network.jinja2 b/wireguard/templates/30-wg0.network.jinja2 new file mode 100644 index 0000000..3e1388e --- /dev/null +++ b/wireguard/templates/30-wg0.network.jinja2 @@ -0,0 +1,5 @@ +[Match] +Name = {{ wg_if }} + +[Network] +Address = {{ wg_net }} diff --git a/wireguard/templates/hostname.wg0.j2 b/wireguard/templates/hostname.wg0.j2 new file mode 100644 index 0000000..18c4b00 --- /dev/null +++ b/wireguard/templates/hostname.wg0.j2 @@ -0,0 +1,5 @@ +wgport {{ wg_port }} wgkey {{ wg_key.content|b64decode }} +{% for peer in wg_peers %} +wgpeer {{ peer.pubkey }} {% for allowed_net in peer.allowed_nets %} wgaip {{ allowed_net }} {% endfor %} +{{ wg_net }} +{% endfor %} diff --git a/wireguard/templates/wg0.conf b/wireguard/templates/wg0.conf new file mode 100644 index 0000000..a0b0e83 --- /dev/null +++ b/wireguard/templates/wg0.conf @@ -0,0 +1,16 @@ +[Interface] +PrivateKey = {{ wg_private_key.stdout_lines[0] }} +ListenPort = {{ wg_port }} + +{% if wg_peers is defined %} +{% for wg_peer in wg_peers %} +[Peer] +PublicKey = {{ wg_peer.pubkey }} +{% for net in wg_peer.allowed_nets %} +AllowedIPs = {{ net }} +{% endfor %} +{% if wg_peer.ip is defined %} +Endpoint = {{ wg_peer.ip }}:{{ wg_peer.port }} +{% endif %} +{% endfor %} +{% endif %}