From e4c49402d73f64b115c77b324b0ab79b6ca6a721 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Wed, 21 Dec 2022 12:14:49 +0100 Subject: [PATCH] add dataset example --- {sbin => ansible/sbin}/build_image | 0 {sbin => ansible/sbin}/diagnose | 0 {sbin => ansible/sbin}/make_changelog | 0 {sbin => ansible/sbin}/make_volatile | 0 {sbin => ansible/sbin}/update_images | 0 doc/README.md | 6 +- doc/dataset_example/README.md | 146 ++ .../seed/caddy-common/applicationservice.yml | 2 + .../caddy-common/dictionaries/20-caddy.yml | 25 + .../manual/image/preinstall/caddy.sh | 1 + .../seed/caddy-common/templates/Caddyfile | 43 + .../caddy-common/templates/sysuser-caddy.conf | 2 + .../caddy-common/templates/tmpfile-caddy.conf | 2 + .../caddy-https-rp/applicationservice.yml | 6 + .../caddy-https-rp/dictionaries/25-caddy.yml | 9 + .../manual/image/preinstall/caddy.sh | 1 + .../caddy-https-rp/patches/Caddyfile.patch | 11 + .../templates/risotto.caddyfile | 20 + .../templates/sysuser-caddy.conf | 2 + .../templates/tmpfile-caddy.conf | 2 + .../seed/caddy-https/applicationservice.yml | 5 + .../caddy-https/dictionaries/25-caddy.yml | 72 + .../manual/image/preinstall/caddy.sh | 1 + .../seed/caddy-https/templates/Caddyfile | 57 + .../seed/caddy-https/templates/ca_HTTP.crt | 1 + .../seed/caddy-https/templates/caddy.crt | 1 + .../seed/caddy-https/templates/caddy.key | 1 + .../caddy-https/templates/risotto.caddyfile | 18 + .../caddy-https/templates/sysuser-caddy.conf | 2 + .../caddy-https/templates/tmpfile-caddy.conf | 2 + doc/dataset_example/servers.yml.caddy-https | 26 + .../servers.yml.caddy-https-rp | 48 + doc/schema.svg | 1927 ++++++++++++----- logo.png | Bin 4405 -> 8552 bytes logo.svg | 83 +- 35 files changed, 1896 insertions(+), 626 deletions(-) rename {sbin => ansible/sbin}/build_image (100%) rename {sbin => ansible/sbin}/diagnose (100%) rename {sbin => ansible/sbin}/make_changelog (100%) rename {sbin => ansible/sbin}/make_volatile (100%) rename {sbin => ansible/sbin}/update_images (100%) create mode 100644 doc/dataset_example/README.md create mode 100644 doc/dataset_example/seed/caddy-common/applicationservice.yml create mode 100644 doc/dataset_example/seed/caddy-common/dictionaries/20-caddy.yml create mode 100644 doc/dataset_example/seed/caddy-common/manual/image/preinstall/caddy.sh create mode 100644 doc/dataset_example/seed/caddy-common/templates/Caddyfile create mode 100644 doc/dataset_example/seed/caddy-common/templates/sysuser-caddy.conf create mode 100644 doc/dataset_example/seed/caddy-common/templates/tmpfile-caddy.conf create mode 100644 doc/dataset_example/seed/caddy-https-rp/applicationservice.yml create mode 100644 doc/dataset_example/seed/caddy-https-rp/dictionaries/25-caddy.yml create mode 100644 doc/dataset_example/seed/caddy-https-rp/manual/image/preinstall/caddy.sh create mode 100644 doc/dataset_example/seed/caddy-https-rp/patches/Caddyfile.patch create mode 100644 doc/dataset_example/seed/caddy-https-rp/templates/risotto.caddyfile create mode 100644 doc/dataset_example/seed/caddy-https-rp/templates/sysuser-caddy.conf create mode 100644 doc/dataset_example/seed/caddy-https-rp/templates/tmpfile-caddy.conf create mode 100644 doc/dataset_example/seed/caddy-https/applicationservice.yml create mode 100644 doc/dataset_example/seed/caddy-https/dictionaries/25-caddy.yml create mode 100644 doc/dataset_example/seed/caddy-https/manual/image/preinstall/caddy.sh create mode 100644 doc/dataset_example/seed/caddy-https/templates/Caddyfile create mode 100644 doc/dataset_example/seed/caddy-https/templates/ca_HTTP.crt create mode 100644 doc/dataset_example/seed/caddy-https/templates/caddy.crt create mode 100644 doc/dataset_example/seed/caddy-https/templates/caddy.key create mode 100644 doc/dataset_example/seed/caddy-https/templates/risotto.caddyfile create mode 100644 doc/dataset_example/seed/caddy-https/templates/sysuser-caddy.conf create mode 100644 doc/dataset_example/seed/caddy-https/templates/tmpfile-caddy.conf create mode 100644 doc/dataset_example/servers.yml.caddy-https create mode 100644 doc/dataset_example/servers.yml.caddy-https-rp diff --git a/sbin/build_image b/ansible/sbin/build_image similarity index 100% rename from sbin/build_image rename to ansible/sbin/build_image diff --git a/sbin/diagnose b/ansible/sbin/diagnose similarity index 100% rename from sbin/diagnose rename to ansible/sbin/diagnose diff --git a/sbin/make_changelog b/ansible/sbin/make_changelog similarity index 100% rename from sbin/make_changelog rename to ansible/sbin/make_changelog diff --git a/sbin/make_volatile b/ansible/sbin/make_volatile similarity index 100% rename from sbin/make_volatile rename to ansible/sbin/make_volatile diff --git a/sbin/update_images b/ansible/sbin/update_images similarity index 100% rename from sbin/update_images rename to ansible/sbin/update_images diff --git a/doc/README.md b/doc/README.md index fb2b79c..f096916 100644 --- a/doc/README.md +++ b/doc/README.md @@ -2,4 +2,8 @@ # Risotto -![Schéma](schema.png "Schéma") +![Schema](schema.png "Schéma") + +# A dataset + +[Dataset example](dataset_example/README.md) diff --git a/doc/dataset_example/README.md b/doc/dataset_example/README.md new file mode 100644 index 0000000..cf2c8d6 --- /dev/null +++ b/doc/dataset_example/README.md @@ -0,0 +1,146 @@ +# Risotto dataset simple examples + +This tutorial aims to show how to deploy a [Caddy](https://caddyserver.com/) server via Risotto. + +Attention it has no other virtues than to be educational. It is not intended for production use. + +## Application services + +The project can be divided into three application services: + +- caddy-common: an application service containing the information common to the two other application services +- caddy-https: a standalone http/https server +- caddy-https-rp: a https only server served behind a reverse proxy + +### caddy-common + +Start by creating the project tree: + +seed/caddy-common/ +├── dictionaries +├── templates +└── manual +    └── image +    └── preinstall + +Then describe the application service in [seed/caddy-common/applicationservice.yml](seed/caddy-common/applicationservice.yml). + +Also a dictionary [seed/caddy-common/dictionaries/20-caddy.yml](seed/caddy-common/dictionaries/20-caddy.yml) with + +- the activation of the caddy service in the "multi-user" target. This service needs some templates: + + - the main configuration's [/etc/caddy/Caddyfile](seed/caddy-common/templates/Caddyfile) to include other /etc/caddy/Caddyfile.d/\*.caddyfile + - /etc/caddy/Caddyfile.d/risotto.caddyfile with appropriate configuration (this file is not part of this application service) + - a [sysusers](https://www.freedesktop.org/software/systemd/man/sysusers.d.html) file [/sysusers.d/0caddy.conf](seed/caddy-common/templates/sysuser-caddy.conf) to create the system user "caddy" + - a [tmpfiles](https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html) file [/tmpfiles.d/0caddy.conf](seed/caddy-common/templates/tmpfile-caddy.conf) to create the directory "caddy_root_directory" and volatile directory "/var/lib/caddy" + +- a family "caddy" (Caddy web server) with a filename variable "caddy_root_directory" (The root path of the site) with default value "/srv/caddy". This variable is not used in this service application + +Finally, create a script to build the image with the caddy package: [seed/caddy-common/manual/image/preinstall/caddy.sh](seed/caddy-common/manual/image/preinstall/caddy.sh). + +### caddy-https + +Start by creating the project tree: + +seed/caddy-https-rp/ +├── dictionaries +└── templates + +Then describe the application service in [seed/caddy-https/applicationservice.yml](seed/caddy-https/applicationservice.yml) with OS and caddy-common dependencies. + +Also create a dictionary [seed/caddy-https/dictionaries/25-caddy.yml](seed/caddy-https/dictionaries/25-caddy.yml) to define the variables: + +- caddy_domain: the domain where Caddy should listen to +- caddy_ca_file, caddy_crt_file and caddy_key_file: certificat for this domain +- redefine the variable incoming_ports to open the ports 80 and 443 + +And new templates: + +- [seed/caddy-https/templates/risotto.caddyfile](seed/caddy-https/templates/risotto.caddyfile) +- [seed/caddy-https/templates/ca_HTTP.crt](seed/caddy-https/templates/ca_HTTP.crt) +- [seed/caddy-https/templates/caddy.key](seed/caddy-https/templates/caddy.key) +- [seed/caddy-https/templates/caddy.crt](seed/caddy-https/templates/caddy.crt) + +### caddy-https-rp + +Start by creating the project tree: + +seed/caddy-https-rp/ +├── dictionaries +└── patches +└── templates + +Then describe the application service in [seed/caddy-https-rp/applicationservice.yml](seed/caddy-https-rp/applicationservice.yml) with OS, caddy-common and reverse-proxy-client dependencies. + +By default, reverse proxy certificate is only readable by "root" user. In the dictionary [seed/caddy-https-rp/dictionaries/25-caddy.yml](seed/caddy-https-rp/dictionaries/25-caddy.yml) we change the user to "caddy". + +And add Caddy configuration's file [seed/caddy-https-rp/templates/risotto.caddyfile](seed/caddy-https-rp/templates/risotto.caddyfile). + +Finally add a patch to modify Caddyfile to not starts Caddy in port 80: [seed/caddy-https-rp/patches/Caddyfile.patch](seed/caddy-https-rp/patches/Caddyfile.patch). +Patches should only use if a template file is define in an other dataset. You should instead add a condition in the template. But for educational reasons we made a patch in this case. + +## Infrastructure + +The infrastructure is define in a uniq YAML file: servers.yml: + +### Zones + +The idea: + +- separate the networks according to the uses +- there is no route to each other + +Ideally only one area has an Internet access. +Internet access is, in fact, firewall rules. +This network is usually called "external". + +The other networks are only there for the communication between server and client. + +The host must have an IP in this network. +IP inside this network are deliver automaticly. + +A network is call a "zone". + +### Modules + +A module is simply a list of application services. An system image is build with informations define in application service. + +### Hosts + +A host is a server on which container or VM are running. +Define the host means define: + +- application services to configure the host and VM +- application service provider to define the provider to apply on each VM +- values to adapt the configuration +- servers, the list of VM with : + + - the corresponding module + - informations (like zone) + - values + +Host must only be a Debian 11 (Bullseye) from now. + +### Examples + +- Caddy as HTTPS server: [servers.yml](servers.yml.caddy-https) +- Caddy behind a Nginx reverse proxy: [servers.yml](servers.yml.caddy-https-rp) + +You must add a index.html file in "/var/lib/risotto/srv/caddy.in.example.net/caddy/". + +## risotto.conf + +```toml +[directories] +datasets = ['/seed', 'seed'] +dest = 'installations' +dest_templates = 'templates' + +[cert_authority] +email = '' +country = 'FR' +locality = 'Dijon' +state = 'France' +org_name = 'Silique' +org_unit_name = 'Cloud' +``` diff --git a/doc/dataset_example/seed/caddy-common/applicationservice.yml b/doc/dataset_example/seed/caddy-common/applicationservice.yml new file mode 100644 index 0000000..aee978d --- /dev/null +++ b/doc/dataset_example/seed/caddy-common/applicationservice.yml @@ -0,0 +1,2 @@ +format: '0.1' +description: Caddy's common files diff --git a/doc/dataset_example/seed/caddy-common/dictionaries/20-caddy.yml b/doc/dataset_example/seed/caddy-common/dictionaries/20-caddy.yml new file mode 100644 index 0000000..298ec27 --- /dev/null +++ b/doc/dataset_example/seed/caddy-common/dictionaries/20-caddy.yml @@ -0,0 +1,25 @@ +services: +- service: + - name: caddy + target: multi-user + file: + - text: /etc/caddy/Caddyfile + engine: 'none' + - text: /etc/caddy/Caddyfile.d/risotto.caddyfile + - text: /sysusers.d/0caddy.conf + source: sysuser-caddy.conf + engine: 'none' + - text: /tmpfiles.d/0caddy.conf + source: tmpfile-caddy.conf + engine: 'none' +variables: +- family: + - name: caddy + description: Caddy web server + variables: + - variable: + - name: caddy_root_directory + type: filename + description: The root path of the site + value: + - text: /srv/caddy diff --git a/doc/dataset_example/seed/caddy-common/manual/image/preinstall/caddy.sh b/doc/dataset_example/seed/caddy-common/manual/image/preinstall/caddy.sh new file mode 100644 index 0000000..b78ac30 --- /dev/null +++ b/doc/dataset_example/seed/caddy-common/manual/image/preinstall/caddy.sh @@ -0,0 +1 @@ +PKG="$PKG caddy" diff --git a/doc/dataset_example/seed/caddy-common/templates/Caddyfile b/doc/dataset_example/seed/caddy-common/templates/Caddyfile new file mode 100644 index 0000000..b29bfac --- /dev/null +++ b/doc/dataset_example/seed/caddy-common/templates/Caddyfile @@ -0,0 +1,43 @@ +# The Caddyfile is an easy way to configure your Caddy web server. +# +# https://caddyserver.com/docs/caddyfile + +#>GNUNUX +# Global options +{ + # remove administration tool + admin off +} +#GNUNUX +#http:// { +#listen only in https +{ + admin off +} + +%for %%domain in %%revprox_client_external_domainnames +https://%%domain { + tls %%revprox_client_cert_file %%revprox_client_key_file { + ca_root %%revprox_client_ca_file + } + log { + output stdout + format console + level info + } +#GNUNUX +# root * /usr/share/caddy + root * /srv/caddy +# + inkscape:zoom="0.38930277" + inkscape:cx="188.79907" + inkscape:cy="724.37194" + inkscape:window-width="1920" + inkscape:window-height="1011" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" + inkscape:showpageshadow="2" + inkscape:deskcolor="#d1d1d1" /> @@ -208,7 +210,7 @@ x2="86.82" y1="14.793" x1="98.330002" - gradientTransform="matrix(0.25589145,0,0,0.25589145,4.141502,17.61046)" + gradientTransform="matrix(0.25589145,0,0,0.25589145,160.88925,-128.76529)" gradientUnits="userSpaceOnUse" id="I" /> @@ -826,7 +828,7 @@ gradientUnits="userSpaceOnUse" cy="441.76999" cx="272.06" - gradientTransform="matrix(0.16746778,0,0,0.13928169,-84.555398,-142.19997)" + gradientTransform="matrix(0.16746778,0,0,0.13928169,-53.438081,-96.738971)" r="103.31" inkscape:collect="always"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + transform="translate(56.083038,244.94272)"> + width="397.836" + height="271.96536" + x="-56.083038" + y="-244.94272" /> user nginx;worker_processes auto;error_log syslog:server=unix:/dev/log;pid /run/nginx.pid;include /usr/share/nginx/modules/*.conf;events {worker_connections 1024;}http {log_format main '$remote_addr - $remote_user'$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log syslog:server=unix:/dev/log combined;error_log syslog:server=unix:/dev/log error;sendfile on;tcp_nopush on;tcp_nodelay on; user nginx;worker_processes auto;error_log syslog:server=unix:/dev/log;pid /run/nginx.pid;include /usr/share/nginx/modules/*.conf;events {worker_connections 1024;}http {log_format main '$remote_addr - $remote_user'$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log syslog:server=unix:/dev/log combined;error_log syslog:server=unix:/dev/log error;sendfile on;tcp_nopush on;tcp_nodelay on; IRAMISU + transform="matrix(0.27056412,0,0,0.27056412,213.06054,-163.45275)"> + transform="matrix(0,-0.27056412,0.27056412,0,234.74769,-107.55541)"> + + + + - - - + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Lstart-5-4-3-7-1);marker-mid:url(#Arrow1Lend-9-0-6-9-9)" + d="m 56.213335,-204.28829 -24.959422,0.27477" + id="path1591-36-6-2-2-9" /> Cheetah + x="224.00247" + y="-5.7337823">Cheetah version: '0.10'# describe a first service with a single fileservices:- service:- name: my_servicefile:- engine: jinjatext: /etc/filename# describe a variable my_first_variable# and a family with a variable my_second_variablevariables:- variable:- name: my_first_variablevalue:- text: my_value- family:- name: my_familyvariables:- variable:- name: my_second_variabletype: numbermandatory: truevalue:- text: 1 version: '0.10'# describe a first service with a single fileservices:- service:- name: my_servicefile:- engine: jinjatext: /etc/filename# describe a variable my_first_variable# and a family with a variable my_second_variablevariables:- variable:- name: my_first_variablevalue:- text: my_value- family:- name: my_familyvariables:- variable:- name: my_second_variabletype: numbermandatory: truevalue:- text: 1 # For more information on configuration,# * Official English Documentation: http:# * Official Russian Documentation: http:%if %%os_name == 'Fedora'user nginx;%elseuser www-data;%end ifworker_processes auto;#GNUNUX error_log /var/log/nginx/error.log;#>GNUNUXerror_log syslog:server=unix:/dev/log;#<GNUNUXpid /run/nginx.pid;# Load dynamic modules. See /usr/share/doc/nginx%if %%os_name == 'Fedora'include /usr/share/nginx/modules/*.conf;%elseinclude /etc/nginx/modules-enabled/*.conf;%end if # For more information on configuration,# * Official English Documentation: http:# * Official Russian Documentation: http:%if %%os_name == 'Fedora'user nginx;%elseuser www-data;%end ifworker_processes auto;#GNUNUX error_log /var/log/nginx/error.log;#>GNUNUXerror_log syslog:server=unix:/dev/log;#<GNUNUXpid /run/nginx.pid;# Load dynamic modules. See /usr/share/doc/nginx%if %%os_name == 'Fedora'include /usr/share/nginx/modules/*.conf;%elseinclude /etc/nginx/modules-enabled/*.conf;%end if user nginx;worker_processes auto;error_log syslog:server=unix:/dev/log;pid /run/nginx.pid;include /usr/share/nginx/modules/*.conf;events {worker_connections 1024;}http {log_format main '$remote_addr - $remote_user'$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log syslog:server=unix:/dev/log combined;error_log syslog:server=unix:/dev/log error;sendfile on;tcp_nopush on;tcp_nodelay on; - - - RISOTTO + d="m -25.714268,-52.802947 5.475011,-0.16233 9.577676,-0.25496 15.6759526,-0.4173 -0.304316,24.322799 -28.7579176,5.532196 -1.144804,-14.509932 -0.426431,-5.404893 z" /> @@ -2791,11 +3165,11 @@ sodipodi:nodetypes="ccccccccc" style="fill:#e6e6e6;stroke:#a1a1a1;stroke-width:0.164917;enable-background:new" inkscape:connector-curvature="0" - d="m -50.600154,-90.425271 0.02234,-7.64447 8.79867,-0.61124 15.675957,-0.4173 -0.304312,24.322801 -28.757919,5.532193 -1.144804,-14.509928 0.508309,-4.514196 z" /> + d="m -19.482837,-44.964347 0.02234,-7.64447 8.79867,-0.61124 15.6759556,-0.4173 -0.304312,24.322801 -28.7579176,5.532193 -1.144804,-14.509928 0.508309,-4.514196 z" /> + d="m -17.092549,-41.741437 5.475011,-0.16233 9.5776747,-0.25496 15.6759553,-0.4173 -0.304316,24.322802 -28.757919,5.53219 -1.144804,-14.50993 -0.426431,-5.40489 z" /> @@ -2864,11 +3238,11 @@ sodipodi:nodetypes="ccccccccc" style="fill:#e6e6e6;stroke:#a1a1a1;stroke-width:0.164917;enable-background:new" inkscape:connector-curvature="0" - d="m -41.978435,-79.363759 0.02234,-7.644472 8.79867,-0.61124 15.675957,-0.4173 -0.304312,24.322802 -28.757919,5.53219 -1.144804,-14.50992 0.508309,-4.5142 z" /> + d="m -10.861118,-33.902835 0.02234,-7.644472 8.7986687,-0.61124 15.6759583,-0.4173 -0.304312,24.322802 -28.757919,5.53219 -1.144804,-14.50992 0.508309,-4.5142 z" /> + d="m -8.4708309,-30.679892 5.4750106,-0.16233 9.577676,-0.25496 15.6759503,-0.4173 -0.304316,24.3227972 -28.7579146,5.5321956 -1.1448046,-14.5099298 -0.426431,-5.404893 z" /> @@ -2937,11 +3311,11 @@ sodipodi:nodetypes="ccccccccc" style="fill:#e6e6e6;stroke:#a1a1a1;stroke-width:0.164917;enable-background:new" inkscape:connector-curvature="0" - d="m -33.356716,-68.302216 0.02234,-7.64447 8.79867,-0.61124 15.6759566,-0.4173 -0.304312,24.322801 -28.7579186,5.532193 -1.144804,-14.509928 0.508309,-4.514196 z" /> + d="m -2.2394003,-22.841292 0.02234,-7.64447 8.79867,-0.61124 15.6759533,-0.4173 -0.304312,24.3227992 -28.7579146,5.5321926 -1.1448046,-14.5099258 0.5083093,-4.514196 z" /> + transform="translate(83.056654,118.48232)"> Rougail + + + + + + + # For more information on configuration,# * Official English Documentation: http:# * Official Russian Documentation: http:%if %%os_name == 'Fedora'user nginx;%elseuser www-data;%end ifworker_processes auto;#GNUNUX error_log /var/log/nginx/error.log;#>GNUNUXerror_log syslog:server=unix:/dev/log;#<GNUNUXpid /run/nginx.pid;# Load dynamic modules. See /usr/share/doc/nginx%if %%os_name == 'Fedora'include /usr/share/nginx/modules/*.conf;%elseinclude /etc/nginx/modules-enabled/*.conf;%end if + servers.json + + + + Dataset + + + + + RISOTTO + + + + + + + + + + + + + + + + + + + diff --git a/logo.png b/logo.png index dd4b631bea6ae6b92d91570edb8713f93aa1b27e..05df3f7259d51690db2edc396e762581cd1230ba 100644 GIT binary patch literal 8552 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 Yj;Id{w`L&$9vVYKMMt?x(JK6Z0Cym5F8}}l literal 4405 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 + inkscape:zoom="4.404458" + inkscape:cx="63.685475" + inkscape:cy="75.378174" + inkscape:window-width="1920" + inkscape:window-height="1011" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" + inkscape:showpageshadow="2" + inkscape:deskcolor="#d1d1d1" /> + width="29.788723" + height="6.963315" + x="78.625404" + y="40.178349" /> + RISOTTO + id="tspan2082">OTTO + + + +