This commit is contained in:
parent
5d742c0bf4
commit
9862b5aa22
19 changed files with 305 additions and 1 deletions
28
content/en/about.md
Normal file
28
content/en/about.md
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
title: "Pierre-Olivier `nemunaire`"
|
||||
date: !!timestamp '2017-07-31T00:50:07+02:00'
|
||||
update: !!timestamp '2021-07-24T00:00:00+01:00'
|
||||
---
|
||||
|
||||
{{<icon "fa fa-briefcase about-icon">}}
|
||||
Currently **entrepreneur** in various businesses. Previously worked as **devops** for [Novaquark](http://novaquark.com), prior to worked as **embedded software engineer** at [Qarnot computing](https://qarnot.com/), then **Chief Information Security Officer** and **senior software architect** at [Qarnot computing](https://qarnot.com/).
|
||||
|
||||
{{<icon "fa fa-graduation-cap about-icon">}}
|
||||
After 5 years in [Epita](http://epita.fr/), in 2014, I am a graduate engineer! I was following the [***System, Network and Security***](https://srs.epita.fr/) classes.
|
||||
{{<br>}}
|
||||
During my studies, I was *root* of the [*assistants'*](https://assistants.epita.fr/) laboratory and of the *System, Network and Security* laboratory.
|
||||
|
||||
{{<icon "fa fa-terminal about-icon">}}
|
||||
With my rich creativity, I'm always working on a lot of amazing projects.
|
||||
I spend most of my free time to improve system support, document and **promote ARM-based computer**, whether server or desktop.
|
||||
{{<br>}}
|
||||
Check out my [gitea instance](https://git.nemunai.re) or my [GitHub account](https://github.com/nemunaire).
|
||||
|
||||
{{<icon "far fa-thumbs-down about-icon">}}
|
||||
You won't find me on any social network, because I don't have time to sell my privacy for free (and I fight against most of them).
|
||||
|
||||
{{<icon "fa fa-heart about-icon">}}
|
||||
I'm crazy about any knowledge (mainly focus on sciences, typography, society, companies, faune and flora, ...) and am looking for more freedom and independence.
|
||||
|
||||
{{<icon "fa fa-drum about-icon">}}
|
||||
On my spare time, I also [play drums](https://storage.nemunai.re/scores/_list.html) and [cook](https://food.p0m.fr/).
|
||||
6
content/en/books.md
Normal file
6
content/en/books.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: "Books"
|
||||
date: !!timestamp '2022-03-02T15:10:10+01:00'
|
||||
---
|
||||
|
||||
I publish my first book in March 2022. It is written in french.
|
||||
41
content/en/post/kernel_configs.md
Normal file
41
content/en/post/kernel_configs.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
title: Linux Kernel Configurations
|
||||
date: !!timestamp '2015-04-20 00:00:00'
|
||||
update: !!timestamp '2019-08-13 14:15:00'
|
||||
tags:
|
||||
- kernel
|
||||
---
|
||||
|
||||
My favorite distribution is [Gentoo], for 7 years now.
|
||||
It allows me to have all the flexibility I need (the perfect world between stability with only legacy packages or recent ones on a constantly broken system; as in Gentoo, you always have choice) and it teaches me so many things each day.
|
||||
|
||||
As I'm used to control everything, here is a list of kernels' configurations I use currently.
|
||||
|
||||
<!--more-->
|
||||
|
||||
* [Dreamplug]: latest public Grsecurity kernel 4.9 (before, I used precompiled kernels from [Xilka]);
|
||||
* [Cubieboard 2]: latest mainline kernel, currently 5.2;
|
||||
* [Odroid-C1]: Linux 3.10 [custom branch](https://github.com/hardkernel/linux.git) for the Amlogic S805 (quad-core ARMv7 Cortex-A5 and Mali450) + upstream patches on 3.10 not merged in the Hardkernel tree;
|
||||
* [Mirabox]: latest public Grsecurity kernel 4.9;
|
||||
* [Cubox-i 4x4]: latest mainline kernel, currently 4.16, running OpenGL applications through etnaviv driver;
|
||||
* [Creator CI20]: Linux 3.18 [custom branch](https://github.com/MIPS/CI20_linux.git) for the Ingenic JZ4780 SoC + [upstream patches](https://github.com/nemunaire/CI20_linux.git) on 3.18 not merged in the imgtec tree;
|
||||
* [ThinkPad X250]: latest mainline kernel, currently 5.1.
|
||||
* [Orange Pi PC]: latest mainline kernel, currently 5.2 on headless server.
|
||||
* [VoltaStream AMP1] & [VoltaStream Zero]: Linux 4.9 [custom branch](https://github.com/polyvection/linux-imx.git) for [i.MX6ULL](http://git.freescale.com/git/cgit.cgi/imx/linux-imx.git) + [upstream patches](https://github.com/nemunaire/linux-imx.git) on 4.9 not merged in the PolyVection tree.
|
||||
* [Pine A64]: latest mainline kernel, currently 5.0 on headless server.
|
||||
* [Helios4]: latest mainline kernel, currently 5.2 on headless server.
|
||||
|
||||
[Gentoo]: http://www.gentoo.org/
|
||||
[Dreamplug]: http://www.globalscaletechnologies.com/p-54-dreamplug-devkit.aspx
|
||||
[Xilka]: http://www.xilka.com/sheeva/
|
||||
[Odroid-C1]: http://www.hardkernel.com/main/products/prdt_info.php?g_code=G141578608433
|
||||
[Cubieboard 2]: http://cubieboard.org/model/cb2/
|
||||
[Mirabox]: http://www.globalscaletechnologies/p-58-mirabox-java-devkit.aspx
|
||||
[Cubox-i 4x4]: http://www.solid-run.com/product/cubox-i-4x4
|
||||
[Creator CI20]: http://store.imgtec.com/uk/product/mips-creator-ci20/
|
||||
[ThinkPad X250]: https://wiki.gentoo.org/wiki/Lenovo_Thinkpad_X250
|
||||
[Orange Pi PC]: http://www.orangepi.org/orangepipc/
|
||||
[VoltaStream AMP1]: https://web.archive.org/web/20190323152013/https://voltastream.com/product/voltastream-amp1/
|
||||
[VoltaStream Zero]: https://web.archive.org/web/20190323152013/https://voltastream.com/product/voltastream-zero/
|
||||
[Pine A64]: https://www.pine64.org/devices/single-board-computers/pine-a64/
|
||||
[Helios4]: https://kobol.io/
|
||||
108
content/en/post/multi-hosts-certificates.md
Normal file
108
content/en/post/multi-hosts-certificates.md
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
title: Multi-Hosts TLS Certificate
|
||||
date: !!timestamp '2022-02-09 00:00:00'
|
||||
tags:
|
||||
- certificates
|
||||
- web
|
||||
---
|
||||
|
||||
It is sometimes convenient to have a domain distributed over two or more machines.
|
||||
This technique, as old as DNS, is interesting to spread the load between multiple hosts, or to provide a bit of high availability.
|
||||
Indeed, if a host becomes inaccessible, at least half of the requests will continue to be successful.
|
||||
|
||||
However, since TLS connections have become the norm, and certificates should be renewed automatically, it could be hard to control the validation and the distribution.
|
||||
|
||||
I will present you a technique which, with the help of a finely configured web server, allows to get a different certificate on each machine, but usable for the same subdomain.
|
||||
|
||||
<!--more-->
|
||||
|
||||
The trick is, when receiving the verification request, to either serve the file if you have it, or to transmit the request to the next server: it will return the file if it has it, or will return a 404 error.
|
||||
|
||||
You have to be careful not to create loops, because you can quickly end up in a situation where no machine has the requested file and therefore calls the next one which does not have it either...
|
||||
|
||||
## Use case
|
||||
|
||||
This trick is helpfull in a small setup: with more than 3 or 4 servers, it is better to use a deployment strategy between hosts, for example based on ACME client hooks: after validation, the client initiates a connection to the other servers to update their certificate and notify their respective web servers.
|
||||
|
||||
I made this installation for my minio servers: each one is accessible through `minio.nemunai.re` but also individually on `minio0.nemunai.re` and `minio1.nemunai.re`. The two servers are in a distinct geographic area, and are not able to execute commands on each other.
|
||||
|
||||
So I tried to create two independent certificates, one for each machine:
|
||||
|
||||
- the first host must obtain a certificate for `minio0.nemunai.re` and `minio.nemunai.re` ;
|
||||
- the second host must obtain a certificate for `minio1.nemunai.re` and `minio.nemunai.re`.
|
||||
|
||||
At the end, each of the two servers will be able to answer the requests of `minio.nemunai.re`, our goal, whatever the status of the other machine.
|
||||
|
||||
Let's Encrypt doesn't revoke certificates already issued for a domain, so both certificates are valid at the same time for the same domain.
|
||||
|
||||
|
||||
## DNS Configuration
|
||||
|
||||
Since we want to keep the architecture simple, we are leaving the load balancing to the DNS: good resolver implementations will do round-robin over our records, ensuring a distribution of clients between each host.
|
||||
|
||||
The first step is to create our sub-domains as follows:
|
||||
|
||||
```
|
||||
minio0.nemunai.re. 3600 IN A 198.51.100.10
|
||||
minio1.nemunai.re. 3600 IN A 198.51.100.11
|
||||
```
|
||||
|
||||
This registers a dedicated domain for each host (so we can access it easily when needed).
|
||||
Then we register the common domain with which we will do load-balancing:
|
||||
|
||||
```
|
||||
minio.nemunai.re. 3600 IN A 198.51.100.10
|
||||
3600 IN A 198.51.100.11
|
||||
```
|
||||
|
||||
We do the same for `AAAA` records, with IPv6 address.
|
||||
|
||||
|
||||
## Reverse Proxy Configuration
|
||||
|
||||
We know that when using the ACME http-01 test, we'll receive a request on `minio.nemunai.re/.well-known/acme-challenge`.
|
||||
But the problem we have to solve is that when one of the servers will ask for a certificate, the validation request has a 50% chance to arrive on the other host.
|
||||
|
||||
This is where we will configure the reverse proxy in order to send the request to the next server if it does not have the answer of the challenge.
|
||||
|
||||
On both servers, we'll handle `acme-challenge` that way:
|
||||
|
||||
```
|
||||
location /.well-known/acme-challenge {
|
||||
alias /var/lib/acme/webroot;
|
||||
|
||||
try_files $uri $uri/ @minio_neighbor;
|
||||
}
|
||||
```
|
||||
|
||||
And we also need that the default server handle `acme-challenge`s in the same directory:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 80 default;
|
||||
|
||||
[...]
|
||||
|
||||
location /.well-known/acme-challenge {
|
||||
alias /var/lib/acme/webroot;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With the [`try_files`](http://nginx.org/en/docs/http/ngx_http_core_module.html#try_files) instruction, our reverse proxy will first look for the file in the local directory, then, if it doesn't exists, it forwards the request to its neighbor server `@minio_neighbor`.
|
||||
|
||||
We declare `@minio_neighbor` in another block:
|
||||
|
||||
```
|
||||
location @storage_neighbor {
|
||||
proxy_pass http://198.51.100.11;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
```
|
||||
|
||||
On the other server, we'll obviously use the address of the other host.
|
||||
|
||||
This configuration avoid infinite proxy loop, as if the challenge response is not find localy, we ask the other host, but it'll not pass through the `try_files` file as this is the default server that'll respond. If it's the other host that have the challenge response, the first server asked will answer it thanks to the proxy, otherwise, the proxify answer will be a 404 error.
|
||||
|
||||
And that's it: we can launch our ACME client on both host, each one can handle the challenge reponse of the other.
|
||||
58
content/en/post/pgp_key.md
Normal file
58
content/en/post/pgp_key.md
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
title: PGP key
|
||||
date: !!timestamp '2015-06-29 00:00:00'
|
||||
update: !!timestamp '2021-07-24 00:45:00'
|
||||
tags:
|
||||
- privacy
|
||||
- cryptography
|
||||
---
|
||||
|
||||
My personal PGP key is the following: [0x842807a84573cc96].
|
||||
|
||||
pub 4096R/4573CC96 2014-06-23 [expires: 2022-06-30]
|
||||
Key fingerprint = E722 B5B7 3CA7 FA93 5FC1 AA09 8428 07A8 4573 CC96
|
||||
uid Pierre-Olivier Mercier <nemunaire@nemunai.re>
|
||||
sub 4096R/9D2855C3 2014-06-23 [expires: 2022-06-30]
|
||||
|
||||
<!--more-->
|
||||
|
||||
I use PGP on a daily basis: each e-mail I sent is at least signed. Don't hesitate to send me encrypted or signed message.
|
||||
|
||||
My keyring is stored on a tamper resistant USB token (a [Nitrokey Pro]).
|
||||
This is the only method I use to sign, encrypt and sometimes to [authenticate](#ssh-authentication).
|
||||
|
||||
|
||||
## DANE
|
||||
|
||||
My key is also available through [OpenPGP DANE].
|
||||
You can retrieve it using `gpg` via:
|
||||
|
||||
```sh
|
||||
gpg2 --auto-key-locate clear,dane -v --locate-key nemunaire@nemunai.re
|
||||
```
|
||||
|
||||
I used [this script](https://gist.github.com/nemunaire/447c989e9f098c679edb) to generate the record.
|
||||
With modern version of `gnupg`, it is also possible to get the DNS entry with the following command:
|
||||
|
||||
```sh
|
||||
gpg2 --export-options export-minimal,export-dane --export 0xKEYID
|
||||
```
|
||||
|
||||
|
||||
## SSH Authentication
|
||||
|
||||
Sometimes I use my dedicated PGP key to log me on a remote SSH server. Here is its corresponding public ssh key :
|
||||
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCnABr9AhXL9AYBQnM0GRcR9yLaKheLcxXykTSEbKP4X/R5BElSS5iF+T+MPi1ym7AtcuFcHXqNdEhb3j6zvqk3sY069sg0zio/jQzWTtKjYVtCiE4SleFrb5I012IwFhPCUArVqhHrfuj8wtg5isl1CSIYii+bpFLbrAGqBcydfcN/Z/vd7jbGEdmHR1RYwE+TzJl1aPiWpqMg9PyaJudNcuxrWjHcHtAomT0CGn2OGREUZS9rcFomCqw7JW9moaWqDSaW+aNX+xTJISo6TiAB4nNOpvTMl6BWPJ5e2eqn4xQACuTb/EVCuAJGeQ8BQudanxRXrfpdgHATsJxldTau2CCmIrZrg2We0ZfiGZ7KEwf3isAyzH9FK/gmb29XeDfvE/UpTTijaPo8xgiH3Ag0ZBk1wb3PVneN9fQGpVogOxR/HwfqOl376N6kTQIhvAFaU/wJnHQ4Z0CBekOxC9XptrihUdW7ashP6arrhYzlyNUPrRGiLmab9jsqsvP7aDRFEpWa/cd9nD2Mp1JNj51ZeqwT5Juo3ElMCfoTy5IAyc6QUTtIdYRgukLjiO8k5NBi8/Yzm1lNzf3cRZdh5ZIS0AUO2Celi97WXiHrU841OqsuMBgdCDnOuG3X8qU+pyT7836XSjglLEwABtXUSWULf06AoPVJe4+cxi3NWfxJiQ==
|
||||
|
||||
|
||||
## Teaching PGP
|
||||
|
||||
Each year, I ask my students at [EPITA](https://www.epita.fr/), a French computer science school, to sign their work when they send them to me, by e-mail.
|
||||
|
||||
As it is not always easy for them, I developed a script to automatically check the correctness of their signature: [peret](https://git.nemunai.re/srs/peret).
|
||||
|
||||
|
||||
[0x842807a84573cc96]: http://pgp.mit.edu/pks/lookup?op=vindex&search=0x842807A84573CC96
|
||||
[Nitrokey Pro]: https://shop.nitrokey.com/shop/product/nitrokey-pro-3
|
||||
[OpenPGP DANE]: https://tools.ietf.org/html/rfc7929
|
||||
27
content/en/post/rtl8153b-for-4.9.md
Normal file
27
content/en/post/rtl8153b-for-4.9.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
title: RTL8153B support for 4.9 kernel
|
||||
date: !!timestamp '2019-03-17 00:00:00'
|
||||
tags:
|
||||
- kernel
|
||||
---
|
||||
|
||||
If you buy a *recent* USB to Ethernet adapter, embedding a Realtek chip, you
|
||||
possibly face, like me, the following error, when connecting it:
|
||||
|
||||
```
|
||||
r8152 4-1.1:1.0 (unnamed net_device) (uninitialized): Unknown version 0x6010
|
||||
r8152 4-1.1:1.0 (unnamed net_device) (uninitialized): Unknown Device
|
||||
```
|
||||
|
||||
<!--more-->
|
||||
|
||||
This error is raised because your Linux r8152 driver is too old and doesn't
|
||||
support your chip's variant.
|
||||
|
||||
In my case, I got the variant `0x6010` which has only been implemented in Linux
|
||||
4.13, in the [commit
|
||||
65b82d69...d3e7fb976](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/net/usb/r8152.c?h=v4.13&id=65b82d696b9e84fda6dd7df61801b57d3e7fb976).
|
||||
|
||||
As I run at the time a 4.9 kernel and can't upgrade to a newer release, I
|
||||
backport the commit to the 4.9 branch. You can find [the patch I made
|
||||
here](r8152-for-4.9.patch). It only adds support for RTL8153B.
|
||||
124
content/en/post/slow-memhog.md
Normal file
124
content/en/post/slow-memhog.md
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
---
|
||||
title: Slow memhog for testing cgroups
|
||||
date: !!timestamp '2016-10-04 00:00:00'
|
||||
tags:
|
||||
- teaching
|
||||
---
|
||||
|
||||
Testing the cgroup memory is not something as easy as we can think. It can't be
|
||||
only question of `malloc(100000)` in a loop, as the Linux kernel overcommit
|
||||
memory allocation: so even if we get effectively a 100000 bytes long memory
|
||||
space, this doesn't decrease the physical available memory. To do so, this
|
||||
space need to be changed pages by pages, that can be tedious to do. And quite
|
||||
uncertain, because the kernel can take advantage of the swap partition...
|
||||
|
||||
To facilitate memory testing, there is `memhog`, part of `numactl` tools. It
|
||||
aims to allocate large memory block for testing, directly in the physical
|
||||
memory.
|
||||
|
||||
<!-- more -->
|
||||
|
||||
If we ask memhog to allocate 100M, 1G, 5G, 10G, ... it'll actually ask the
|
||||
kernel for such amont of memory, in no time. If there is enough memory
|
||||
available, we got our 100M, 1G, 5G, ... and the available memory is really
|
||||
decreased by such volume.
|
||||
|
||||
In my demos, I need a slightly different behaviour, to demonstrate what happens
|
||||
as a function of time.
|
||||
|
||||
I slightly modify `memhog` to introduce a timer between slice allocation.
|
||||
|
||||
```c
|
||||
/* Derivative work of memhog.c from the numactl repository,
|
||||
hosted at https://github.com/numactl/numactl.git
|
||||
|
||||
Copyright (C) 2016 Pierre-Olivier Mercier, EPITA.
|
||||
Copyright (C) 2003,2004 Andi Kleen, SuSE Labs.
|
||||
|
||||
numactl 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; version
|
||||
2.
|
||||
numactl 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 find a copy of v2 of the GNU General Public License somewhere
|
||||
on your Linux system; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
char *
|
||||
alloc_workbuf(size_t size)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
/* allocate some memory */
|
||||
ptr = malloc(size);
|
||||
|
||||
/* return NULL on failure */
|
||||
if (ptr == NULL)
|
||||
{
|
||||
fprintf(stderr, "Unable to malloc %zuk: %s\n", size / 1024, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* lock this buffer into RAM */
|
||||
if (mlock(ptr, size)) {
|
||||
free(ptr);
|
||||
if (errno == ENOMEM)
|
||||
fprintf(stderr, "Unable to lock memory: not enough permissions\n");
|
||||
else
|
||||
perror("Unable to lock memory");
|
||||
return NULL;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
size_t size;
|
||||
size_t steps = 32;
|
||||
|
||||
/* parse arguments */
|
||||
if (argc < 2 || argc > 3) {
|
||||
fprintf(stderr, "Usage: memhog <size in MB> [nb steps]\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
size = atoi(argv[1]);
|
||||
if (argc > 2)
|
||||
steps = atoi(argv[2]);
|
||||
|
||||
size = size / steps;
|
||||
|
||||
/* Do stuff */
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
{
|
||||
if (!alloc_workbuf(size * 1000000UL))
|
||||
break;
|
||||
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
|
||||
usleep(80000);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
You can compile those C lines with just `make`, stating your file is named `memhog.c`:
|
||||
|
||||
```shell
|
||||
make memhog
|
||||
```
|
||||
75
content/en/post/ssh_keys.md
Normal file
75
content/en/post/ssh_keys.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
title: My private SSH keys managment
|
||||
date: !!timestamp '2015-02-19 00:00:00'
|
||||
update: !!timestamp '2017-07-23 22:45:00'
|
||||
tags:
|
||||
- cryptography
|
||||
- ssh
|
||||
---
|
||||
|
||||
I always have a different SSH key pair per machine. The aim is to really never copy my private key from a machine to another over network or USB stick.
|
||||
|
||||
<!--more-->
|
||||
|
||||
## Client keys
|
||||
|
||||
With this approach, if one of my host is compromised and/or my key could have been exposed, I have only to remove granted access to this key to host or services (OK, that can be painful to find such services), but I can continue to use other no-compromised keys to work.
|
||||
|
||||
As you can see on my [github](https://github.com/nemunaire.keys) account, I've registered several keys, because I don't work from the same machine every time.
|
||||
|
||||
It can sometime be complicated to give me access to machine, but in most case, I tend to centralize most of my outgoing connections from a single host, which is in fact my home desktop: oupaout.
|
||||
|
||||
Here is a list of my keys' md5 fingerprints:
|
||||
|
||||
* `assouan`
|
||||
* [`aton`](aton_ed25519.pub): 0d:89:02:4a:45:51:0c:43:e8:be:2e:99:38:5b:88:0e (ED25519)
|
||||
* [`aton`](aton_rsa.pub): ee:61:d5:bf:b0:23:93:1a:bb:32:ef:34:10:fb:aa:77 (RSA 4096)
|
||||
* `bastet` (legacy): 4a:51:80:24:b0:69:7a:59:fc:44:08:29:aa:15:42:5b (RSA 4096)
|
||||
* EPITA personal rack (legacy): 91:95:bc:4e:e7:b2:5b:9c:7f:71:4a:7d:0a:43:80:17 (RSA 4096)
|
||||
* EPITA SSH gate (legacy)
|
||||
* EPITA YACKU laboratory (legacy): 80:7c:8e:42:53:ee:0f:b5:27:d5:63:ab:b4:5a:46 (RSA 4096)
|
||||
* [`khonsou`](khonsou_ed25519.pub): 0d:89:02:4a:45:51:0c:43:e8:be:2e:99:38:5b:88:0e (ED25519)
|
||||
* khonsou_old: f5:dc:fd:db:c8:ce:ec:df:33:86:54:58:05:7e:d2:74 (ED25519)
|
||||
* `montou`: this machine can't be used as outgoing host.
|
||||
* `nout`: this machine can't be used as outgoing host.
|
||||
* `nout_old`: e8:69:71:3c:5e:cc:3c:d5:7d:a2:67:30:a9:35:df:24 (RSA 4096)
|
||||
* [`ouaset`](ouaset.pub): 5e:01:65:8c:ae:9e:6e:f3:a5:88:80:16:fa:bf:d6:ac (ED25519)
|
||||
* [`oupaout`](oupaout.pub): 30:04:ad:11:57:e0:e9:dc:a2:e0:d2:65:cd:60:9a:ab (ED25519)
|
||||
* [Rescue key](rescue.pub): 30:15:a7:3f:0b:51:7a:53:7b:47:bd:00:21:55:ee:bd (RSA 4096)
|
||||
* `satis`: this machine has no key pair yet.
|
||||
* [`seth`](seth_ed25519.pub): 6a:1f:05:60:fa:6b:32:f3:2d:ba:e3:36:e7:6b:7b:13 (ED25519)
|
||||
* [`seth`](seth_rsa.pub): 03:a9:3a:3a:e1:e0:99:24:69:15:cb:a5:58:5c:3f:6c (RSA 4096)
|
||||
* `seth_old`: 97:8c:bc:9a:ec:62:8d:b8:1a:88:b1:0d:d9:62:1a:04 (RSA 4096)
|
||||
|
||||
### Get the fingerprint from a private or public key file
|
||||
|
||||
```sh
|
||||
ssh-keygen -l -E md5 -f KEY_FILE
|
||||
```
|
||||
|
||||
|
||||
### Usign PGP
|
||||
|
||||
Sometime, I use my authentication PGP key as SSH key. Read the [related article]({{< relref "/post/pgp_key.md#ssh-authentication" >}}) to view the public key.
|
||||
|
||||
|
||||
## Server keys
|
||||
|
||||
The `nemunai.re` domain, contains [SSHFP] records for each physical host. To avoid answering this message without further checks:
|
||||
|
||||
The authenticity of host 'nemunai.re (203.0.113.42)' can't be established.
|
||||
RSA key fingerprint is 00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff.
|
||||
Are you sure you want to continue connecting (yes/no)?
|
||||
|
||||
you can use the following command: `ssh -o "VerifyHostKeyDNS yes" $HOSTNAME.nemunai.re`
|
||||
|
||||
[SSHFP]: http://tools.ietf.org/html/rfc4255
|
||||
|
||||
|
||||
### Generate SSHFP records
|
||||
|
||||
SSHFP records can be generated with the following command:
|
||||
|
||||
```sh
|
||||
ssh-keygen -r HOSTNAME
|
||||
```
|
||||
70
content/en/post/use-additional-ipv6-blocks-from-isp.md
Normal file
70
content/en/post/use-additional-ipv6-blocks-from-isp.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
---
|
||||
title: Use the additional IPv6 blocks of the Free and Orange network
|
||||
date: !!timestamp '2023-04-05 14:43:00'
|
||||
tags:
|
||||
- network
|
||||
- ipv6
|
||||
- freebox
|
||||
---
|
||||
|
||||
With Free and Orange, when IPv6 is not disabled, the Freebox (and some Livebox) provide a /64 IPv6 range to the connected equipment.
|
||||
But it turns out that it is a /60 range that is available and usable by each subscriber.
|
||||
This represents a total of 8 addressable /64 networks.
|
||||
Let's see what it can be used for and how to use it.
|
||||
|
||||
<!-- more -->
|
||||
|
||||
# IPv6 reminders
|
||||
|
||||
Contrary to IPv4, with IPv6 one avoids making NAT, i.e. one allocates to each machine on the network an IPv6 address directly routable on Internet.
|
||||
Of course it is always necessary to go through the router (the box) which is then used as a simple gateway to the Internet.
|
||||
|
||||
In IPv6, devices are able to choose their own IP, without the help of the DHCP protocol.
|
||||
This is possible because the router regularly transmits information about the subnet in which you are located (this is the [Router Advertisement (RA)](https://en.wikipedia.org/wiki/Router_advertisement)).
|
||||
|
||||
For our experiment, let's take the following lab:
|
||||
|
||||

|
||||
|
||||
We have all our equipment connected to the box and a series of virtual machines hosted on one of the network machines.
|
||||
|
||||
At this stage, if we want our virtual machines to be reachable from the Internet in IPv6, we have to configure the hypervisor network in *bridge* mode.\
|
||||
Indeed if the network of our virtual machines is distinct from the network of the box, this one will not be able to communicate with our virtual machines. By using the *bridge* mode, we simulate the fact that the virtual machine is diconnected to the box, or to a switch. In any case no equipment requiring to make routing.
|
||||
|
||||
If our virtual machines are only IPv6 clients and are not intended to serve content directly on the Internet, this solution is perfectly acceptable. But if we want to serve content, we might want to segment our network to try to isolate the content. But if we want to serve content, we might want to segment our network to try to isolate the devices.
|
||||
|
||||
|
||||
# Segment the network of the box
|
||||
|
||||
Because of the very large number of public IPv6 addresses that our operators provide us with, we could start by segmenting our network between our virtual servers and our other equipment: each would be in a separate subnet.
|
||||
|
||||
The main interest of this segmentation would be to avoid that all this little world shares the same subnet: as they can all communicate directly with each other, it is more complicated to filter efficiently malicious exchanges. For example, if one of the virtual machines exposed on the Internet is compromised, it can access all our local equipment (telephones, connected objects, etc.) which are not necessarily secure, or conversely, an object on the network can start to intercept all the data. network object can start intercepting all the traffic of the virtual machines by pretending to be the box.
|
||||
|
||||
We could therefore want to segment our network like this:
|
||||
|
||||

|
||||
|
||||
We would reserve half of the /64 block for real network equipment and allocate the other half to our virtual machines located on a server/Raspberry Pi.
|
||||
|
||||
Despite the large number of IPv6 addresses that can be assigned, it is not easy to subdivide our /64 to assign it to a secondary router or a virtual machine server. This segmentation is indeed not possible without changing the configuration of the box because it expects to be able to reach our virtual machines directly, without going through an intermediate machine/host/router.
|
||||
|
||||
However, we have access to the routing parameters of the other 7 /64 blocks distributed by the operator. We can for example assign one of them to the host of our virtual machines.
|
||||
|
||||
|
||||
# Delegate an additional IPv6 prefix
|
||||
|
||||
As mentioned in the introduction, some operators make available to their subscribers a range of IPv6 addresses much larger than the /64 block of the main network.
|
||||
|
||||
Some ISP routers also make it possible to take advantage of additional blocks by offering to delegate the other blocks to machines on the network.
|
||||
|
||||
In concrete terms, this means that when the box receives a packet destined for one of the delegated blocks, it will not process it itself, but will transmit it to the machine designated as the recipient. In other words, it will route the traffic of this block to the designated router. And it doesn't have to be complicated!
|
||||
|
||||
|
||||
# Different use cases
|
||||
|
||||
Now that we have seen the theory, let's look at different use cases, so we are not limited to our virtual machines:
|
||||
|
||||
- Use a /64 block to give IPv6 to its virtual machines
|
||||
- [Use a /64 block to give IPv6 to your Docker containers]({{< relref "use-ipv6-in-docker.md" >}})
|
||||
- Use a /64 block to have IPv6 in several isolated subnets
|
||||
- Use a /64 block to have public IPv6 in your Wireguard tunnel
|
||||
44
content/en/post/use-gitolite-access-control-in-gitweb.md
Normal file
44
content/en/post/use-gitolite-access-control-in-gitweb.md
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
title: Use Gitolite Access Control In Gitweb
|
||||
date: !!timestamp '2015-09-24 00:00:00'
|
||||
update: !!timestamp '2019-04-09 12:45:00'
|
||||
tags:
|
||||
- git
|
||||
---
|
||||
|
||||
Are you using gitolite and gitweb? Two nice and lightweight projects, but perhaps you are tired to manage access control in gitweb?
|
||||
|
||||
Here is some simple tricks to use gitolite access list directly into gitweb, automatically.
|
||||
|
||||
<!--more-->
|
||||
|
||||
As you may know, the configuration file
|
||||
[`/etc/gitweb.conf`](https://git.kernel.org/pub/scm/git/git.git/tree/Documentation/gitweb.conf.txt#n15)
|
||||
is in fact no less than a perl script fragment. As it is simply imported by
|
||||
gitweb, it is possible to include some code.
|
||||
|
||||
[Gitolite](https://gitolite.com/) is also a piece of software writen in
|
||||
Perl. So it is pretty easy to make gitweb relying on gitolite permissions. Here
|
||||
is what I append to my `/etc/gitweb.conf`:
|
||||
|
||||
```perl
|
||||
# Most of the code comes from https://gitolite.com/gitolite/gitweb.conf.html
|
||||
# where comments live.
|
||||
|
||||
BEGIN {
|
||||
$ENV{HOME} = "/var/lib/gitolite"; # Home of the gitolite user in gentoo
|
||||
$ENV{GL_BINDIR} = "/usr/libexec/gitolite";
|
||||
}
|
||||
|
||||
use Gitolite::Easy;
|
||||
|
||||
$ENV{GL_USER} = $cgi->remote_user || "gitweb";
|
||||
|
||||
$export_auth_hook = sub {
|
||||
my $repo = shift;
|
||||
|
||||
return unless $repo =~ s/^\Q$projectroot\E\/?(.+)\.git$/$1/;
|
||||
|
||||
return Gitolite::Easy::can_read($repo);
|
||||
};
|
||||
```
|
||||
138
content/en/post/use-ipv6-in-docker.md
Normal file
138
content/en/post/use-ipv6-in-docker.md
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
---
|
||||
title: Give IPv6 connectivity to its Docker containers using an IPv6 block from its ISP
|
||||
date: !!timestamp '2023-05-04 15:10:00'
|
||||
tags:
|
||||
- network
|
||||
- ipv6
|
||||
- docker
|
||||
---
|
||||
|
||||
It may seem surprising that a modern service like Docker does not offer IPv6 in containers by default, especially when in a network with IPv6.
|
||||
|
||||
In fact, for the same reason we saw in [the introductory article]({{< relref "use-additional-ipv6-blocks-from-isp.md" >}}), since the containers are in a virtual network, they cannot be reached by the box/router distributing the IPv6 subnet.
|
||||
|
||||
<!-- more -->
|
||||
|
||||
The same phenomenon can be observed with IPv4: each container has an IPv4 in a subnet separate from the one in which our host machine is located.
|
||||
|
||||

|
||||
|
||||
In order for the containers to have access to the Internet under these conditions, in IPv4 NAT is implemented:
|
||||
|
||||
```
|
||||
42sh$ iptables -t nat -vnL POSTROUTING
|
||||
Chain POSTROUTING (policy ACCEPT 3 packets, 228 bytes)
|
||||
pkts bytes target prot opt in out source destination
|
||||
14713 978K MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
|
||||
```
|
||||
|
||||
Since NAT is generally not done on IPv6, nothing similar is done by Docker in this sense.
|
||||
|
||||
|
||||
# Docker as IPv6 router
|
||||
|
||||
Without IPv6 in a container, it is impossible for containers to address other services listening exclusively in IPv6 on the Internet.
|
||||
|
||||
In order for containerized programs to be able to connect to other services in IPv6, the *Enable IPv6* option must be activated and the prefix to be used must be defined through the *IPv6 Prefix* option.
|
||||
|
||||
Be careful, it is not enough to define these options, it is also necessary that the box correctly routes the packets to the destinations of the containers to your machine.
|
||||
|
||||
This is why we need to take advantage of the other IPv6 blocks provided by our operator. By telling the box the address of the machine hosting our containers, it will route all packets to the containers without question.
|
||||
|
||||
So not everything can be done exclusively on the machine, the network must also be configured. Let's start with that.
|
||||
|
||||
|
||||
# Set up IPv6 prefix delegation on the Freebox
|
||||
|
||||
The router will ask us for the address (IPv6) to which it should route the packets. We usually indicate a [local link IP](https://en.wikipedia.org/wiki/Link-local_address).
|
||||
|
||||
So we start by looking at our local IPv6 on the outgoing link to the router.
|
||||
|
||||
⚠️ Be careful, all interfaces have a local address, they all start with `fe80:`, they are only valid on the network card considered. If you get the wrong address, nothing will happen (it won't break your network though).
|
||||
|
||||
In my case, it is the `eth0` interface that is connected to the router:
|
||||
|
||||
```
|
||||
42sh$ ip address show eth0
|
||||
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
|
||||
link/ether fd:54:01:98:cd:ba brd ff:ff:ff:ff:ff:ff
|
||||
inet 192.168.0.42/24 brd 192.168.0.255 scope global dynamic noprefixroute eth0
|
||||
valid_lft 35141sec preferred_lft 35141sec
|
||||
inet6 2a01:...:2420:24ac:f101:c280:50c2/64 scope global noprefixroute
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fe80::5a43:3580:173c:395e/64 scope link noprefixroute
|
||||
valid_lft forever preferred_lft forever
|
||||
```
|
||||
|
||||
My local IP is therefore `fe80::5a43:3580:173c:395e`.
|
||||
|
||||
It is this IP that I will indicate in the configuration of the router.
|
||||
|
||||
On the Freebox, the window for setting additional prefixes is in "Paramètres de la Freebox", "Configuration IPv6", under the "Général" tab. It is the "Délégation de préfixe" box that will interest us.
|
||||
|
||||
It looks like this:
|
||||
|
||||

|
||||
|
||||
Always leave the first field empty, otherwise the box will not offer you IPv6 on the main network.
|
||||
|
||||
Indicate in the next empty field (normally the second one!) the local address retrieved earlier.
|
||||
|
||||
That's all! The hardest part is over. Now let's see the Docker configuration.
|
||||
|
||||
|
||||
# Setting up Docker for IPv6
|
||||
|
||||
We will not use the range to which our machine is connected. We are going to use a whole /64 range, the one for which we have given the local IP of our machine to the box.
|
||||
|
||||

|
||||
|
||||
According to the previous screenshot, our configuration file `/etc/docker/daemon.json` should look like:
|
||||
|
||||
```
|
||||
{
|
||||
"ipv6": true,
|
||||
"fixed-cidr-v6": "2a01:1234:abcd:2421::/64"
|
||||
}
|
||||
```
|
||||
|
||||
We restart Docker and we can test:
|
||||
|
||||
```
|
||||
42sh$ docker run -it alpine
|
||||
/ # ip address show eth0
|
||||
58: eth0@if59: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
|
||||
link/ether 02:42:ac:11:00:09 brd ff:ff:ff:ff:ff:ff
|
||||
inet 172.17.0.9/16 brd 172.17.255.255 scope global eth0
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 2a01:1234:abcd:2421:0:242:ac11:9/64 scope global flags 02
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fe80::42:acff:fe11:9/64 scope link
|
||||
valid_lft forever preferred_lft forever
|
||||
```
|
||||
|
||||
If you have an IPv6 in addition to the usual IPv4, Docker is correctly configured. To find out if the configuration on the box side was successful, let's do a `ping` in the container:
|
||||
|
||||
```
|
||||
/ # ping ping6.online.net
|
||||
PING ping6.online.net (2001:bc8:1::40): 56 data bytes
|
||||
64 bytes from 2001:bc8:1::40: seq=0 ttl=52 time=11.008 ms
|
||||
64 bytes from 2001:bc8:1::40: seq=1 ttl=52 time=8.822 ms
|
||||
^C
|
||||
--- ping6.online.net ping statistics ---
|
||||
2 packets transmitted, 2 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 8.822/9.915/11.008 ms
|
||||
```
|
||||
|
||||
If the ping responds, it's all good: your containers will now have access to and be accessible in IPv6.
|
||||
|
||||
|
||||
# Others use cases
|
||||
|
||||
This post is part of a series of posts on the use of additional IPv6 ranges:
|
||||
|
||||
- [Introduction: Use the additional IPv6 blocks of the Free and Orange network]({{< relref "use-additional-ipv6-blocks-from-isp.md" >}})
|
||||
- Use a /64 block to give IPv6 to its virtual machines
|
||||
- Use a /64 block to give IPv6 to your Docker containers
|
||||
- Use a /64 block to have IPv6 in several isolated subnets
|
||||
- Use a /64 block to have public IPv6 in your Wireguard tunnel
|
||||
29
content/en/post/user-ns-for-grsecurity.md
Normal file
29
content/en/post/user-ns-for-grsecurity.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
title: Support for the user namespace in grsecurity kernel
|
||||
date: !!timestamp '2018-10-31 00:00:00'
|
||||
tags:
|
||||
- kernel
|
||||
---
|
||||
|
||||
Grsecurity has completely disabled, [on
|
||||
purpose](https://forums.grsecurity.net/viewtopic.php?f=3&t=3929#p13904), the
|
||||
user namespace code for the kernel.
|
||||
|
||||
As the goal of this namespace is to gain (virtualy) root privilegies inside a
|
||||
namespace (in theory, it shouldn't give more priviledgies than the one you
|
||||
initialy have outside of your namespace), there are some interesting use cases,
|
||||
or, in my case I need to perform some demo in front of my students.
|
||||
|
||||
<!--more-->
|
||||
|
||||
Other distros, like Debian, choose to allow the use of user namespace through a
|
||||
custom kernel config variable. In order to use them without both
|
||||
`CAP_SYS_ADMIN`, `CAP_SETUID` and `CAP_SETGID`, you need to activate (as root):
|
||||
|
||||
```bash
|
||||
42sh# sysctl -w kernel.unprivileged_userns_clone=1
|
||||
```
|
||||
|
||||
To reproduce the same behaviour with a grsecurity kernel, I made a patch, to
|
||||
apply after the grsecurity patch:
|
||||
[grsec-enable-user-ns.patch](grsec-enable-user-ns.patch).
|
||||
38
content/en/talks.md
Normal file
38
content/en/talks.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
title: "Talks"
|
||||
date: !!timestamp '2017-07-31T00:07:37+02:00'
|
||||
---
|
||||
|
||||
Here are slides I used as support to my presentations:
|
||||
|
||||
* [[FR] Strong authentication](2fa.pdf)
|
||||
* [[FR] Self-Hosting](autohebergement.pdf)
|
||||
* [[FR] DNS overview](QTechNote%20DNS.pdf)
|
||||
* [[FR] Docker hands-on](QTechNote%20Docker.pdf)
|
||||
* [[FR] gRPC/Protobuf overview](QTechNote%20%231.pdf)
|
||||
|
||||
|
||||
## Teaching
|
||||
|
||||
In [Epita](http://www.epita.fr/), I'm responsible for teaching containers usage and plumbing in a 15 hours course called [*light virtualization*](https://virli.nemunai.re/) and for [*ADvanced LINux administration*](https://adlin.nemunai.re).
|
||||
|
||||
Moreover, I coach students to create [an annual CTF](https://fic.srs.epita.fr/), at [FIC].
|
||||
And also lead the related CTF [server developments](https://git.nemunai.re/fic/server).
|
||||
|
||||
[FIC]: https://www.forum-fic.com/
|
||||
|
||||
|
||||
## Ideas
|
||||
|
||||
Following, some talks I started to work on:
|
||||
|
||||
* SSL client good practices (from Internet browser view)
|
||||
* Unix daemons in systemd epoch
|
||||
* HTTP/2
|
||||
* Feedbacks on 5 years of self-hosting
|
||||
* Feedbacks on 1 year without Intel CPU
|
||||
* Linux PAM, how to
|
||||
* Demystied Gentoo
|
||||
* Git advanced usages by example
|
||||
* Packets filtering via nftables
|
||||
* The e-mail tech, today
|
||||
Loading…
Add table
Add a link
Reference in a new issue