feat: Base rainbowsheep-cloud ansible playbooks and roles

This commit is contained in:
Paul Breugnot 2026-10-19 14:24:03 +02:00
commit 494e748beb
12 changed files with 345 additions and 0 deletions

73
README.md Normal file
View file

@ -0,0 +1,73 @@
# Rainbowsheep Cloud Server :sheep: :rainbow:
Ansible recipes to install and maintain an instance of the Rainbowsheep cloud.
The Rainbowsheep cloud is a very lightweight and secured data cloud based on
standard or widely available tools such as NFS, Kerberos and gocryptfs.
It is an alternative to heavy cloud infrastructure such as NextCloud that
requires databases, web clients and so on.
The Rainbowsheep cloud is accessible as a regular Linux file system. This allows
to easily connect to the cloud with standard Linux tools, and to easily and
efficiently perfom complex operations on files if required.
## Server structure
Data for all users are stored in the following directories:
```
/srv
├── protected
│ ├── user1
│ ├── user2
│ └── ...
└── vault
├── user1
├── user2
└── ...
```
Data in `/srv/protected` is stored as plain files on the server, so this
endpoint must be served using `krb5p`, i.e. Kerberos authentication and
encryption. This means your data is securely transmitted and other users cannot
have access to your data, but a `root` user on the server can read it.
Data in `/srv/vault` is encrypted at the filesystem level using `gocryptfs`.
This means you need your own private password to access your data locally. Only
uncrypted data is visible from the server, even for `root` user. In consequence,
the `/srv/vault` endpoint can be securely served using `krb5`, i.e. Kerberos
authentication only, as transmitted data is the `gocryptfs` encrypted data.
# Configure
Initialize the Kerberos master password:
```bash
ansible-vault encrypt_string --ask-vault-pass --stdin-name "krb5_master_password" --output krb5_master_password.yaml
```
# Install
Install cloud using Ansible:
```bash
ansible-playbook -i inventory -e "@krb5_master_password.yml" --ask-vault-pass rainbowsheep-cloud.yml
```
# Create user
```bash
export RAINBOW_NEW_USER=...
```
Initialize user password:
```bash
ansible-vault encrypt_string --ask-vault-pass --stdin-name "password" --output $RAINBOW_NEW_USER.yml
echo "username=$RAINBOW_NEW_USER" >> $RAINBOW_NEW_USER.yml
```
Deploy the new user:
```bash
ansible-playbook -i inventory -e "@$RAINBOW_NEW_USER.yml" create-user.yml
```
Once created, the specified password can be used on client side for Kerberos
authentication (`kinit`) and to mount the `gocryptfs` vault.

65
create-user.yml Normal file
View file

@ -0,0 +1,65 @@
- name: Create new Rainbosheep cloud user
hosts: server
tasks:
- name: Create kerberos user
ansible.builtin.command:
cmd: "kadmin.local add_principal -pw '{{ password }}' {{ username }}"
register: create_krb_user_out
failed_when: create_krb_user_out.rc != 0 and create_krb_user_out.rc != 1
changed_when: create_krb_user_out.rc == 0
- name: Create linux group
ansible.builtin.group:
name: "{{ username }}"
- name: Create linux user
ansible.builtin.user:
name: "{{ username }}"
create_home: false
group: "{{ username }}"
- name: Create user protected repository
ansible.builtin.file:
path: "/srv/protected/{{ username }}"
state: directory
owner: "{{ username }}"
group: "{{ username }}"
mode: "770"
- name: Create user vault repository
ansible.builtin.file:
path: "/srv/vault/{{ username }}"
state: directory
owner: "{{ username }}"
group: "{{ username }}"
mode: "770"
- name: Init gocryptfs vault
ansible.builtin.command:
cmd: "gocryptfs --init /srv/vault/{{ username }}"
stdin: "{{ password }}\n"
register: gocryptfs_out
failed_when: gocryptfs_out.rc != 0 and gocryptfs_out.rc != 6
changed_when: gocryptfs_out.rc == 0
- name: Get gocryptfs master key
ansible.builtin.command:
cmd: "gocryptfs-xray -dumpmasterkey /srv/vault/{{ username }}/gocryptfs.conf"
stdin: "{{ password }}\n"
register: master_key
- name: Print master key
ansible.builtin.debug:
msg: |
Your master key is:
{{ master_key.stdout }}
If the gocryptfs.conf file becomes corrupted or you ever forget your password,
there is only one hope for recovery: The master key. Print it to a piece of
paper and store it in a drawer.
- name: Log master key
ansible.builtin.debug:
msg: "{{ gocryptfs_out }}"

8
rainbowsheep-cloud.yml Normal file
View file

@ -0,0 +1,8 @@
- name: Rainbowsheep Cloud Server
hosts: server
roles:
- chrony
- kerberos
- nfs
- vault

View file

@ -0,0 +1,22 @@
---
# tasks file for chrony_client
- name: Install chrony
ansible.builtin.apt:
name: chrony
state: present
update_cache: yes
# - name: Configure chrony client
# ansible.builtin.template:
# src: chrony.conf.j2
# dest: /etc/chrony/chrony.conf
# owner: root
# group: root
# mode: "0644"
# notify: Restart chrony
- name: Enable and start chrony
ansible.builtin.service:
name: chrony
state: started
enabled: yes

View file

@ -0,0 +1,2 @@
kerberos_realm: "{{ ansible_facts['hostname'] }}"

View file

@ -0,0 +1,8 @@
- name: Restart krb5 kdc
ansible.builtin.service:
name: krb5-kdc
state: restarted
- name: Restart krb5 admin server
ansible.builtin.service:
name: krb5-admin-server
state: restarted

View file

@ -0,0 +1,76 @@
- name: Install Kerberos server
ansible.builtin.apt:
pkg:
- krb5-user
- krb5-kdc
- krb5-admin-server
state: present
update_cache: yes
- name: Enables krb5-kdc
ansible.builtin.service:
name: krb5-kdc
enabled: true
- name: Enables krb5-admin-server
ansible.builtin.service:
name: krb5-admin-server
enabled: true
- name: Configure krb5
ansible.builtin.template:
src: krb5.conf.j2
dest: /etc/krb5.conf
owner: root
group: root
mode: "0644"
notify:
- Restart krb5 kdc
- Restart krb5 admin server
- name: Configure krb5 kdc
ansible.builtin.template:
src: kdc.conf.j2
dest: /etc/krb5kdc/kdc.conf
owner: root
group: root
mode: "0644"
notify:
- Restart krb5 kdc
- Restart krb5 admin server
- name: Configure krb5 ACLs
# Allow */admin (notable root/admin) user to manage principals
ansible.builtin.template:
src: kadm5.acl.j2
dest: /etc/krb5kdc/kadm5.acl
owner: root
group: root
mode: "0644"
notify:
- Restart krb5 kdc
- Restart krb5 admin server
- name: Create kdc
ansible.builtin.command:
cmd: "kdb5_util create -P {{ krb5_master_password }}"
register: create_kdc
failed_when: create_kdc.rc != 0 and create_kdc.rc != 1
changed_when: create_kdc.rc == 0
- name: Create kdc stash file
# The stash file is specified in kdc.conf as key_stash_file
ansible.builtin.command:
cmd: "kdb5_util stash -P {{ krb5_master_password }}"
- name: Start krb5-kdc
ansible.builtin.service:
name: krb5-kdc
state: started
- name: Start krb5-admin-server
ansible.builtin.service:
name: krb5-admin-server
state: started

View file

@ -0,0 +1 @@
*/admin@{{ kerberos_realm | upper }} *

View file

@ -0,0 +1,21 @@
[kdcdefaults]
kdc_ports = 750,88
[realms]
{{ kerberos_realm | upper }} = {
database_name = /var/lib/krb5kdc/principal
admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab
acl_file = /etc/krb5kdc/kadm5.acl
key_stash_file = /etc/krb5kdc/stash
kdc_ports = 750,88
max_life = 3d 0h 0m 0s
max_renewable_life = 7d 0h 0m 0s
#master_key_type = aes256-cts
#supported_enctypes = aes256-cts:normal aes128-cts:normal
default_principal_flags = +preauth
}
[logging]
kdc = CONSOLE
kdc = FILE:/var/log/kdc.log
debug = true

View file

@ -0,0 +1,28 @@
[libdefaults]
default_realm = {{ kerberos_realm | upper }}
dns_lookup_realm = true
dns_lookup_kdc = true
# The following krb5.conf variables are only for MIT Kerberos.
kdc_timesync = 1
ccache_type = 4
forwardable = true
proxiable = true
rdns = false
ticket_lifetime = 3d
renew_lifetime = 7d
# The following libdefaults parameters are only for Heimdal Kerberos.
fcc-mit-ticketflags = true
[realms]
{{ kerberos_realm | upper }} = {
kdc = kerberos.{{ kerberos_realm }}
admin_server = kerberos.{{ kerberos_realm }}
default_principal_flags = +preauth
}
[domain_realm]
{{ kerberos_realm }} = {{ kerberos_realm | upper }}
.{{ kerberos_realm }} = {{ kerberos_realm | upper }}

36
roles/nfs/tasks/main.yml Normal file
View file

@ -0,0 +1,36 @@
---
- name: Install nfs server
ansible.builtin.apt:
name: nfs-kernel-server
state: present
update_cache: yes
- name: Create /srv/protected export
ansible.builtin.file:
state: directory
path: /srv/protected
- name: Export /srv/protected
ansible.builtin.lineinfile:
path: /etc/exports
regexp: '^/srv/protected'
line: /srv/protected *(rw,sync,sec=krb5p,no_subtree_check)
- name: Create /srv/vault export
ansible.builtin.file:
state: directory
path: /srv/vault
- name: Export /srv/vault
ansible.builtin.lineinfile:
path: /etc/exports
regexp: '^/srv/vault'
line: /srv/vault *(rw,sync,sec=krb5p:krb5i:krb5,no_subtree_check)
- name: Enable and start NFS server
ansible.builtin.service:
name: nfs-kernel-server
state: started
enabled: yes

View file

@ -0,0 +1,5 @@
- name: Install gocryptfs
ansible.builtin.apt:
name: gocryptfs
update_cache: true