A linear congruence can be displayed as
$$
ax \equiv b (\text{mod } m )
$$
By definition of congruence, $ ax \equiv b (\text{mod } m ) $ iff $ax - b$ is disible by $m$. According to Wikipedia, the earliest known statement of the Chinese Remainder Theorem is by the Chinese mathematician Sun-tzu in the Sun-tzu Suan-ching in the 3rd century AD.
$$
今有物不知其數,三三數之剩二,五五數之剩三,七七數之剩二,問物幾何?
$$
We can rewrite the above statement into below congruence equations.
$$
x \equiv 2 (\text{mod } 3 )
$$
$$
x \equiv 3 (\text{mod } 5 )
$$
$$
x \equiv 2 (\text{mod } 7 )
$$
and the answer is $23$. In fact, this is the minimum possible solution. Starting from 23, you can get another possible answer by adding 105, i.e.
$$
x = 23 + 105 * n
$$
where
$$
n \in {0, 1, 2, 3, \cdots}
$$
Given a set of congruence equations, we are interested to find $a$ that produces the given remainders.
$$
a \equiv a_1 (\text{mod } p_1 )
$$
$$
a \equiv a_2 (\text{mod } p_2 )
$$
$$
\cdots \\
$$
$$
a \equiv a_k (\text{mod } p_k )
$$
where every pair $p_i$ are pairwise coprime, $a_i$ are given constants.
## Problem: [Oversleeping](https://atcoder.jp/contests/abc193/tasks/abc193_e)
In this problem, we are interested in finding the minimum non-negative integer t such that
$$
X \le t \text{ mod } (2X + 2Y) \lt X + Y
$$
$$
P \le t \text{ mod } (P + Q) \lt P + Q
$$
We can solve this problem using Chinese Remainder Theorem.
$$
t \equiv t_1 (\text{mod } 2X + 2Y )
$$
$$
t \equiv t_2 (\text{mod } P + Q )
$$
AtCoder has provided a crt library [here](https://github.com/atcoder/ac-library/blob/master/atcoder/math.hpp#L34), which makes the implementation relatively simple.
```cpp
#include <atcoder/math>
using namespace atcoder;
const ll mx = numeric_limits<ll>::max();
void solve() {
ll X, Y, P, Q;
cin >> X >> Y >> P >> Q;
ll ans = mx;
for(ll t1 = X; t1 < X + Y; t1++) {
for(ll t2 = P; t2 < P + Q; t2++) {
auto [t, lcm] = crt(
{ t1, t2 }, // rem
{ 2 * X + 2 * Y, P + Q } // mod
);
if(lcm == 0) {
// no solution
continue;
}
MIN(ans, t);
}
}
if(ans == mx) OUT("infinity");
else OUT(ans);
}
```
The full solution is available [here](https://github.com/wingkwong/competitive-programming/blob/master/atcoder/contests/abc193/E.cpp).
Sunday, 28 February 2021
Monday, 15 February 2021
Sealed Secrets Example
Demonstrating how to use ``sealed-secrets`` to encrypt and store Kubernetes secrets in git on a k3s cluster using k3d. The full source code can be found [here](https://github.com/wingkwong/sealed-secrets-example).
# What Problem does sealed-secrets Solve?
Secrets cannot be managed in git. Sealed Secrets can help encrypt your Secrets into SealedSecret which is safe to store in a public repository. It can be decrypted only by the controller running in the target cluster.
# Install k3d
k3d is a little helper to run k3s in docker, where k3s is the lightweight Kubernetes distribution by Rancher. It actually removes millions of lines of code from k8s. If you just need a learning playground, k3s is definitely your choice.
Check out [k3d Github Page](https://github.com/rancher/k3d#get) to see the installation guide.
> When creating a cluster, ``k3d`` utilises ``kubectl`` and ``kubectl`` is not part of ``k3d``. If you don't have ``kubectl``, please install and set up [here](https://kubernetes.io/docs/tasks/tools/install-kubectl/).
Once you've installed ``k3d`` and ``kubectl``, run
```
➜ k3d create -n sealed-secrets-example
```
We need to make ``kubectl`` to use the kubeconfig for that cluster.
```
➜ export KUBECONFIG="$(k3d get-kubeconfig --name='sealed-secrets-example')"
```
# Install kubeseal
The kubeseal utility is the first part of Sealed Secrets, and it uses asymmetric crypto to encrypt secrets that only the controller can decrypt.
```
➜ brew install kubeseal
```
# Apply sealed-secrets controller
The second part of Sealed Secrets is a cluster-side controller / operator.
```
➜ kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.14.1/controller.yaml
rolebinding.rbac.authorization.k8s.io/sealed-secrets-controller created
clusterrolebinding.rbac.authorization.k8s.io/sealed-secrets-controller created
serviceaccount/sealed-secrets-controller created
customresourcedefinition.apiextensions.k8s.io/sealedsecrets.bitnami.com created
rolebinding.rbac.authorization.k8s.io/sealed-secrets-service-proxier created
role.rbac.authorization.k8s.io/sealed-secrets-service-proxier created
role.rbac.authorization.k8s.io/sealed-secrets-key-admin created
clusterrole.rbac.authorization.k8s.io/secrets-unsealer created
deployment.apps/sealed-secrets-controller created
service/sealed-secrets-controller created
```
```
➜ kubectl logs --tail=-1 -f -l name=sealed-secrets-controller -n kube-system
```
```
controller version: v0.14.1
2021/02/15 04:24:29 Starting sealed-secrets controller version: v0.14.1
2021/02/15 04:24:29 Searching for existing private keys
2021/02/15 04:24:32 New key written to kube-system/sealed-secrets-keynvpcz
2021/02/15 04:24:32 Certificate is
-----BEGIN CERTIFICATE-----
MIIErjCCApagAwIBAgIRAIh+6dntUQrrqSAWQ4gcwJ8wDQYJKoZIhvcNAQELBQAw
ADAeFw0yMTAyMTUwNDI0MzJaFw0zMTAyMTMwNDI0MzJaMAAwggIiMA0GCSqGSIb3
DQEBAQUAA4ICDwAwggIKAoICAQDxXLMWTnq5Z42APQ6pZZGTAaXS1BsNDOcJuIIE
Yv+bqKS0tb1cTbXDCpPxxqCj35iuI/jLy9LhjqTlzJFtDevUf2F2b2RzvRaEtHIY
pvAXMfNCVTkUMOuTGB72rTLx2KI1mYg6OI+PDh26BrWkxlbW8oFe7knoeXO3n6dJ
j8W9Ypg5ZXNxLqcagk/HmSAoGLQkzaq9rQiVVM2jA+LPUImH4jIph9BYvWjL+cLv
ax0WhybTYk/YAb+/4sV7OMI6AHl4e8jNgrVVj3DdWDhv3sNmuxshk0OypZ2fwrqV
s9N8so+7JADWQnXw1MTOAec4CS6RbVLl3RTwegDszgpZ9jXafy0WH3CNrdeVSJUl
3NJ8Qy40Y1mnrz3Qa+TbGjV9LTn2FpC3g59Zib2mtb62RYy0jOko54MjURtUao/n
p26P1/BtkPN024hpNngbKwN5JluNdeP6KDFiLwsAsYGs/YhyVoUa7vo+iMmHNwVr
FsyaGOEPSPRdi6KXj/HgxYAxMNpYY6b41rvOeQ1paf4c9f6L7NJamKyM+a8R/zt7
F06c7aHJFdvU4M4bMbRqVC7jmRa8y6fPRu/9jSfQ1lR2B1BJgEAGbk149bvbWiZ9
jP+vz5T3qLpWVqv05RTdAfusEDcmImSbrzSU3l2y67nmshAkPoZpM8PqBSVfrA6N
R99tiwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAAEwDwYDVR0TAQH/BAUwAwEB/zAN
BgkqhkiG9w0BAQsFAAOCAgEAxLMHynW7ZzAEVblRnB8bydlcCG4ddSTghLh085vN
OkzQOLDDaC++vTWzQA6CWyzNNkpuXpp9r3tzy6qcFvYfXSJrT1ZwyzWzgv2K+Bjm
M/OuLtOYLNT4L2SZxIPSc60lUn77RV11I7dFY3UNkqRvH7Gu+qQSYZFU1PZSTt5n
BSXHT2/+GaVD9bdK9/lfF6vNDeut3iEfY9pi3BR8d3G/EDz9B5fS/NPXV8gzXPUf
Bth3bUIZv+a06PNO7t02RarkskN7JIOb1WniYUjWxdYq7PGR6yriItGvLdRzrX9s
wtWrrUfhBSbNJW5CYMjZyxPQDdrh0SGm2aiAUTQux++jS63cehhhjAUSvKiklCEg
i2uuq5VuV1cbyq8gf3jCFXh9d5EjJE4eCMUEamh3NwIc2Tbl4C+KarVNxgFvPL8+
Nmnc8aVgHISuVxxcUz28Q0//I8VZrcsyw0b4T7X5exRRcEk0bW/CzX+Tqrjk3Pep
6FKvQP1iXV5WIocodGoMmOBhhihNjZOWugaaQpk41PCUqMkOnOyXmQ8bLI7E/wvB
VpDKjKQeCRbUAkDmFgRHoT8jYkaEeI43G2kWQTlPACNY6spsabKDw570j8gzHUTn
kEsUTISM/1/lnTpMV3me24VEDOlUFELBp/kXx3QAA0xO5IpHdaIMnse68oVIT9kZ
PBc=
-----END CERTIFICATE-----
2021/02/15 04:24:32 HTTP server serving on :8080
```
# Verify the sealed-secrets controller
```
➜ kubectl get pods -n kube-system
```
```
sealed-secrets-controller-59f9b7b6f4-4qsbq 1/1 Running 1 2m20s
```
```
➜ kubectl get secrets -n kube-system
```
```
sealed-secrets-controller-token-27cjx kubernetes.io/service-account-token 3 4m29s
sealed-secrets-keynvpcz kubernetes.io/tls 2 3m33s
```
Take a look at the secret ``sealed-secrets-keynvpcz``
```
➜ kubectl get secrets sealed-secrets-keynvpcz -n kube-system -o yaml
```
```
apiVersion: v1
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVyakNDQXBhZ0F3SUJBZ0lSQUloKzZkbnRVUXJycVNBV1E0Z2N3Sjh3RFFZSktvWklodmNOQVFFTEJRQXcKQURBZUZ3MHlNVEF5TVRVd05ESTBNekphRncwek1UQXlNVE13TkRJME16SmFNQUF3Z2dJaU1BMEdDU3FHU0liMwpEUUVCQVFVQUE0SUNEd0F3Z2dJS0FvSUNBUUR4WExNV1RucTVaNDJBUFE2cFpaR1RBYVhTMUJzTkRPY0p1SUlFCll2K2JxS1MwdGIxY1RiWERDcFB4eHFDajM1aXVJL2pMeTlMaGpxVGx6SkZ0RGV2VWYyRjJiMlJ6dlJhRXRISVkKcHZBWE1mTkNWVGtVTU91VEdCNzJyVEx4MktJMW1ZZzZPSStQRGgyNkJyV2t4bGJXOG9GZTdrbm9lWE8zbjZkSgpqOFc5WXBnNVpYTnhMcWNhZ2svSG1TQW9HTFFremFxOXJRaVZWTTJqQStMUFVJbUg0aklwaDlCWXZXakwrY0x2CmF4MFdoeWJUWWsvWUFiKy80c1Y3T01JNkFIbDRlOGpOZ3JWVmozRGRXRGh2M3NObXV4c2hrME95cFoyZndycVYKczlOOHNvKzdKQURXUW5YdzFNVE9BZWM0Q1M2UmJWTGwzUlR3ZWdEc3pncFo5alhhZnkwV0gzQ05yZGVWU0pVbAozTko4UXk0MFkxbW5yejNRYStUYkdqVjlMVG4yRnBDM2c1OVppYjJtdGI2MlJZeTBqT2tvNTRNalVSdFVhby9uCnAyNlAxL0J0a1BOMDI0aHBObmdiS3dONUpsdU5kZVA2S0RGaUx3c0FzWUdzL1loeVZvVWE3dm8raU1tSE53VnIKRnN5YUdPRVBTUFJkaTZLWGovSGd4WUF4TU5wWVk2YjQxcnZPZVExcGFmNGM5ZjZMN05KYW1LeU0rYThSL3p0NwpGMDZjN2FISkZkdlU0TTRiTWJScVZDN2ptUmE4eTZmUFJ1LzlqU2ZRMWxSMkIxQkpnRUFHYmsxNDlidmJXaVo5CmpQK3Z6NVQzcUxwV1ZxdjA1UlRkQWZ1c0VEY21JbVNicnpTVTNsMnk2N25tc2hBa1BvWnBNOFBxQlNWZnJBNk4KUjk5dGl3SURBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQUFFd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTgpCZ2txaGtpRzl3MEJBUXNGQUFPQ0FnRUF4TE1IeW5XN1p6QUVWYmxSbkI4YnlkbGNDRzRkZFNUZ2hMaDA4NXZOCk9relFPTEREYUMrK3ZUV3pRQTZDV3l6Tk5rcHVYcHA5cjN0enk2cWNGdllmWFNKclQxWnd5eld6Z3YySytCam0KTS9PdUx0T1lMTlQ0TDJTWnhJUFNjNjBsVW43N1JWMTFJN2RGWTNVTmtxUnZIN0d1K3FRU1laRlUxUFpTVHQ1bgpCU1hIVDIvK0dhVkQ5YmRLOS9sZkY2dk5EZXV0M2lFZlk5cGkzQlI4ZDNHL0VEejlCNWZTL05QWFY4Z3pYUFVmCkJ0aDNiVUladithMDZQTk83dDAyUmFya3NrTjdKSU9iMVduaVlVald4ZFlxN1BHUjZ5cmlJdEd2TGRSenJYOXMKd3RXcnJVZmhCU2JOSlc1Q1lNalp5eFBRRGRyaDBTR20yYWlBVVRRdXgrK2pTNjNjZWhoaGpBVVN2S2lrbENFZwppMnV1cTVWdVYxY2J5cThnZjNqQ0ZYaDlkNUVqSkU0ZUNNVUVhbWgzTndJYzJUYmw0QytLYXJWTnhnRnZQTDgrCk5tbmM4YVZnSElTdVZ4eGNVejI4UTAvL0k4VlpyY3N5dzBiNFQ3WDVleFJSY0VrMGJXL0N6WCtUcXJqazNQZXAKNkZLdlFQMWlYVjVXSW9jb2RHb01tT0JoaGloTmpaT1d1Z2FhUXBrNDFQQ1VxTWtPbk95WG1ROGJMSTdFL3d2QgpWcERLaktRZUNSYlVBa0RtRmdSSG9UOGpZa2FFZUk0M0cya1dRVGxQQUNOWTZzcHNhYktEdzU3MGo4Z3pIVVRuCmtFc1VUSVNNLzEvbG5UcE1WM21lMjRWRURPbFVGRUxCcC9rWHgzUUFBMHhPNUlwSGRhSU1uc2U2OG9WSVQ5a1oKUEJjPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS0FJQkFBS0NBZ0VBOFZ5ekZrNTZ1V2VOZ0QwT3FXV1Jrd0dsMHRRYkRRem5DYmlDQkdML202aWt0TFc5ClhFMjF3d3FUOGNhZ285K1lyaVA0eTh2UzRZNms1Y3lSYlEzcjFIOWhkbTlrYzcwV2hMUnlHS2J3RnpIelFsVTUKRkREcmt4Z2U5cTB5OGRpaU5abUlPamlQanc0ZHVnYTFwTVpXMXZLQlh1NUo2SGx6dDUrblNZL0Z2V0tZT1dWegpjUzZuR29KUHg1a2dLQmkwSk0ycXZhMElsVlROb3dQaXoxQ0poK0l5S1lmUVdMMW95L25DNzJzZEZvY20wMkpQCjJBRy92K0xGZXpqQ09nQjVlSHZJellLMVZZOXczVmc0Yjk3RFpyc2JJWk5Ec3FXZG44SzZsYlBUZkxLUHV5UUEKMWtKMThOVEV6Z0huT0FrdWtXMVM1ZDBVOEhvQTdNNEtXZlkxMm44dEZoOXdqYTNYbFVpVkpkelNmRU11TkdOWgpwNjg5MEd2azJ4bzFmUzA1OWhhUXQ0T2ZXWW05cHJXK3RrV010SXpwS09lREkxRWJWR3FQNTZkdWo5ZndiWkR6CmROdUlhVFo0R3lzRGVTWmJqWFhqK2lneFlpOExBTEdCclAySWNsYUZHdTc2UG9qSmh6Y0ZheGJNbWhqaEQwajAKWFl1aWw0L3g0TVdBTVREYVdHT20rTmE3em5rTmFXbitIUFgraSt6U1dwaXNqUG12RWY4N2V4ZE9uTzJoeVJYYgoxT0RPR3pHMGFsUXU0NWtXdk11bnowYnYvWTBuME5aVWRnZFFTWUJBQm01TmVQVzcyMW9tZll6L3I4K1U5Nmk2ClZsYXI5T1VVM1FIN3JCQTNKaUprbTY4MGxONWRzdXU1NXJJUUpENkdhVFBENmdVbFg2d09qVWZmYllzQ0F3RUEKQVFLQ0FnQWF4eVViV1hPbU5FWHZyMVo4RnNleTNxRHVKaGdtTjRNK2dkank4YVRZT1Rxa3pmRUhWNXZOMnRPVgpKR3RZSXd1R2JubEE2d2tuZXpMeVIrTHVqWGZYcUpaQWxKVTVmZ1lNalJTSGhhWG5mT1EzUE10TFlTNFJzTUJtCnI4cVNLRzIrc3B6NWtLTGt4VFVwR1d0M3I0V2M3V1RMQ25icXN1YlN2WVRLMVllanZsZVRMcDFETm1EVndSVm0KMktkSHE0MzQ4MVI1SE1SeUJPbVhwMnUzZ29EdnNYbk5QOE11eFR6bVBIeVRJWGdsc3JMdEN1QSszOXJOU0RTTwp1anBhUXdrM0E4ekFlRHIwRmlqNGRidzFOU3JLc0FHUGxRNFN1T3NtK1d6SUJSNTJuRHowRDBlRWZmVWwxZ1ZMCnNjeGNYREJ0ZEFxWmRCREpxVStHOWtrUnVBNDdTMjZMSEg0RHhMZUlrcGQ0U3pYajNSa0IybENpeVhCZGpvZGcKaVRsSXNlQkl5OWpTcUltdDUrMS9oMlJKK2pSOVVpSTJuYWtlUDNNRWFHUDNaR0dWd1lFRkQ0UFVpdkhWUHl3aAppTCtaK2dqL3hDSGdrK0x5U2NHMXZXT0I2L2ljWjd1MXJ1czZ2Y0ZDdWpaSWoweWx1eGp3ejFlTU9XUmdvQ0VpClhmOGRsaVJTQVV4L204Slg5RTFYU2ZzRDQxZzZQZFZWeGlONFFORGpkZ2tzQVorVjNKVlc5QUNlWEY5ZFU3NGgKSnFSOFhKWU5Lbng2cUZtZURObXV5WXVEa245NmRlVHErS2xKT3NMb3ZEVDR6M1VNVzA5VEVwclVmdGxaSStaZApwenJZaGlVKzBiaUdTOVhVN0dyUkNzN3IrRm5KTGF1TDN3bloxUFk0SXpJaWJZOXFtUUtDQVFFQTk0Q3VjRmJxCmVTVkhJakxxdXV1eHJpT2I5TDRVZDhxdk1DcDAyZHdTRWZaY2VCcUE1NmdVa01RZ2dCQ1BYbWJOT1dRbkgyYloKUU8xOEJSWTRjbkdMVzZEL3EwYVhiQzh2WEFDVlpzZnBYcldxbjNTSGNjOWZpNnZlOGlHNGtKZEVOUmRnQlU4VwpsR2o3aDhTZ2lHSkNzbHQvTTdtZ0lqa0FCZ0xNQitsRUFrSzBWa0pJVEE0N0xzRlNScElMTnJhUkt2aG5INUVQCkVoVlViazNYZm5XSkJOTTZyci9pb1NicjgvWU1uZENZbzlBWFJOalFmU0RmMHBVYWpSNmJraXBnVVZiUDliZGYKNVhyZ2MxSlNQQlVUTkxSR3hNVEhXTlgrbGJzcWhpQysrU3RZUTN3dmFCZXBOemZ0cXhVV0lXTzNKbXVyV3BUYQpQZ1NyOTYwVVpJbjhIUUtDQVFFQSthWU1ZeSs5Ty9sWWRpb1Q0dWhFZVZaQ2pDcGdhSVpham1aUnp6SXA5eVFaCm9jam1aRk1seXJKYUlmaFNyMHFKZVZtSWtGQ0tyNDdaY0ROaGhtMFV0cWlPbGovQWtuQWowQkV1b1UwYTVxSFkKR0M2UnZVUG1xSEVTRTR5Zmpub1huczB6VnFRN1krSEhUNWR5Y2NpZzJxYUZaNk8vR3BoUUZVd01mMG41eHd3Kwo2WCtPam50eTREUTd4MmwzOGNRUmYrdkh3MGhuWllBcllqZytmR0QzQ0ZpeDZueVVtRDg1amErTURmckNOTkFBCnpZMyszV0FPQzJ1L3lNSjRydjVmazJyajBRNU5sN3NRc1Fwc3Q5WGhiTHNUTWRmeDNqQmdxbXFsN2J5Vnp3MloKM29JdFlncjVCZmtLS3lIOC9RMndMMndOeVRXQ1l6MWtyclBmZnZYUHh3S0NBUUJIMFg1TXVOdlhCWHNyc0V5dQpxci9uUVF2N0s4RHl0Y3k2RkVmT0ErNzJhVitSdGxjYllZbCtMSHNsemloY0EwYWYxYkVJaXFhV0VaT0FRbDlrCnpnL2JLYyttbXBoTDJ6Rko2QjF5TXFaRVJrRFpmazNqTjRLSkcvbFlsM0pmK3BUZk53WTA1Q3N3SzNwNWZoUDcKSDFBdFF5R1pGODhndnh1RG93SWpkWXUzZ0RXbUpodW1maWFzUFlxclVhdVJWODZ1QW1DaUoweVJPY0ZETkxGSQpUOERQdHA5N245Q2FaSm5wTThlYmI3RXJMN0hnMTIxQU1lN2d3MFZ1RjZpYTlGTDRwMUUzQXR2LzBmVVpZWlRkClBGeFRXZENEUG5wK0M3S1JManQ3cWpyZ1FMU2UrSVVsRm1DUzFsYlA0eEdGNU5KN2dwaTVjeUlWQnZRRHJhU1MKTy92OUFvSUJBUURGeXYxOWlGRlJ0eGlUWm5zakNBdFlaek9LZ2Zpb1YrcGZjRW5ZODFHMGNYR3RjTks1SWZlTApSUXVNWm9aOFEzM3dHelBMdzBSZUc3dkMzYktqSXNHS2hybVI2U2pWM090QzZwb2JTay9KOHVpWElDNXYyZUJpCkRGUGFFVXhKUWdwODB1K2Q4YmpzUmZIMzZYSFBITG4xQW9JbnZ1Q21YWTcxa0s5R0dvSS9aa0JpRjZJRzJXQUcKcXR2Qi9wbjlmdTZ1ZjB4aU9IZFRQOTBma0poUlN6SHQ5dmZmWkowR2t2RXloS2RlWEJLS2JWSjFpYzhuN2ZheQpyY2ZoYzlMU01zL2VxSTJmRU1vQk1VRGtRL0luSk5uWm44NXhhenBDWStueW0xU2pxd3EyWlh4SGdyUWFQYjlYCk1CMFNWM2R0dHU2a1krUDRTdURuWjdqaGdibk5pVXY1QW9JQkFEU0JKRUxCVkJBOS9QU0lSYXpDNmlCVm5vckoKamd6TUQxbVcrM0JYOUFFK0pOWm5QMGtqaHp2TTJ1QU1PRFRWbVJQNkF5d2ZlbGVlR0Vjc2MzSHhNKzBtQXdCdQpOY2FEbXR5aTVMbmoxSXM2VEltOWEwR0dFYWJRQjVzbFJtUU5GUFVjeFBKVGF2R0dwYWZxckxoZkJWRXYxU3lUCldiRDhyT2Yxd2QyMzZYYkl1SDhPZnU1WGtJVUR5dFdVMk8rNkN4bFJCZmFKNkQvUk1VQWk1TlZJY09ybjhxUnkKU3hNcFpBY3hBd1BpVmNVL3NSc0JqWVdPdTNleXIrcjdKZktUdnB2dTI3a1l6ODZFMlhDZUtZblpock85WDN1YgpseGN6WW9CaFpaeGRIRjdmRnoyb29UZUlxVEtKNkx4OFF2N1VHR2lhUmdIN3hrMmQ5MWdWejBGRmVKVT0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K
kind: Secret
metadata:
creationTimestamp: "2021-02-15T04:24:32Z"
generateName: sealed-secrets-key
labels:
sealedsecrets.bitnami.com/sealed-secrets-key: active
name: sealed-secrets-keynvpcz
namespace: kube-system
resourceVersion: "1141"
selfLink: /api/v1/namespaces/kube-system/secrets/sealed-secrets-keynvpcz
uid: fd35e6a1-6cb9-4a9c-b50c-91a9a03f6cd5
type: kubernetes.io/tls
```
# Create Namespace for testing sealed-secrets
```
➜ kubectl apply -f k3s/02-namespace.yaml
namespace/foo created
```
Verify it by running
```
➜ kubectl get ns
NAME STATUS AGE
default Active 27m
kube-system Active 27m
kube-public Active 27m
kube-node-lease Active 27m
foo Active 41s
```
# Create Secret
Create a regular Secret as a template to seal it later
```
➜ echo -n 'sealed-secrets-example' | base64
c2VhbGVkLXNlY3JldHMtZXhhbXBsZQ==
```
Replace ```` with the generated toke in ``03-secret.yaml``
```
➜ kubectl apply -f k3s/03-secret.yaml
secret/credentials created
```
# Configure sealed-secrets
We need the key certificate to seal secrets. We can use ``kubeseal`` to fetch it from the controller at runtime or we can store it locally using the below command and use it offline.
```
➜ kubeseal --controller-namespace kube-system --fetch-cert > cert.pem
```
Decode the certificate to take a look
```
➜ openssl x509 -in cert.pem -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
88:7e:e9:d9:ed:51:0a:eb:a9:20:16:43:88:1c:c0:9f
Signature Algorithm: sha256WithRSAEncryption
Issuer:
Validity
Not Before: Feb 15 04:24:32 2021 GMT
Not After : Feb 13 04:24:32 2031 GMT
Subject:
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:
00:f1:5c:b3:16:4e:7a:b9:67:8d:80:3d:0e:a9:65:
91:93:01:a5:d2:d4:1b:0d:0c:e7:09:b8:82:04:62:
ff:9b:a8:a4:b4:b5:bd:5c:4d:b5:c3:0a:93:f1:c6:
a0:a3:df:98:ae:23:f8:cb:cb:d2:e1:8e:a4:e5:cc:
91:6d:0d:eb:d4:7f:61:76:6f:64:73:bd:16:84:b4:
72:18:a6:f0:17:31:f3:42:55:39:14:30:eb:93:18:
1e:f6:ad:32:f1:d8:a2:35:99:88:3a:38:8f:8f:0e:
1d:ba:06:b5:a4:c6:56:d6:f2:81:5e:ee:49:e8:79:
73:b7:9f:a7:49:8f:c5:bd:62:98:39:65:73:71:2e:
a7:1a:82:4f:c7:99:20:28:18:b4:24:cd:aa:bd:ad:
08:95:54:cd:a3:03:e2:cf:50:89:87:e2:32:29:87:
d0:58:bd:68:cb:f9:c2:ef:6b:1d:16:87:26:d3:62:
4f:d8:01:bf:bf:e2:c5:7b:38:c2:3a:00:79:78:7b:
c8:cd:82:b5:55:8f:70:dd:58:38:6f:de:c3:66:bb:
1b:21:93:43:b2:a5:9d:9f:c2:ba:95:b3:d3:7c:b2:
8f:bb:24:00:d6:42:75:f0:d4:c4:ce:01:e7:38:09:
2e:91:6d:52:e5:dd:14:f0:7a:00:ec:ce:0a:59:f6:
35:da:7f:2d:16:1f:70:8d:ad:d7:95:48:95:25:dc:
d2:7c:43:2e:34:63:59:a7:af:3d:d0:6b:e4:db:1a:
35:7d:2d:39:f6:16:90:b7:83:9f:59:89:bd:a6:b5:
be:b6:45:8c:b4:8c:e9:28:e7:83:23:51:1b:54:6a:
8f:e7:a7:6e:8f:d7:f0:6d:90:f3:74:db:88:69:36:
78:1b:2b:03:79:26:5b:8d:75:e3:fa:28:31:62:2f:
0b:00:b1:81:ac:fd:88:72:56:85:1a:ee:fa:3e:88:
c9:87:37:05:6b:16:cc:9a:18:e1:0f:48:f4:5d:8b:
a2:97:8f:f1:e0:c5:80:31:30:da:58:63:a6:f8:d6:
bb:ce:79:0d:69:69:fe:1c:f5:fe:8b:ec:d2:5a:98:
ac:8c:f9:af:11:ff:3b:7b:17:4e:9c:ed:a1:c9:15:
db:d4:e0:ce:1b:31:b4:6a:54:2e:e3:99:16:bc:cb:
a7:cf:46:ef:fd:8d:27:d0:d6:54:76:07:50:49:80:
40:06:6e:4d:78:f5:bb:db:5a:26:7d:8c:ff:af:cf:
94:f7:a8:ba:56:56:ab:f4:e5:14:dd:01:fb:ac:10:
37:26:22:64:9b:af:34:94:de:5d:b2:eb:b9:e6:b2:
10:24:3e:86:69:33:c3:ea:05:25:5f:ac:0e:8d:47:
df:6d:8b
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Encipher Only
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
c4:b3:07:ca:75:bb:67:30:04:55:b9:51:9c:1f:1b:c9:d9:5c:
08:6e:1d:75:24:e0:84:b8:74:f3:9b:cd:3a:4c:d0:38:b0:c3:
68:2f:be:bd:35:b3:40:0e:82:5b:2c:cd:36:4a:6e:5e:9a:7d:
af:7b:73:cb:aa:9c:16:f6:1f:5d:22:6b:4f:56:70:cb:35:b3:
82:fd:8a:f8:18:e6:33:f3:ae:2e:d3:98:2c:d4:f8:2f:64:99:
c4:83:d2:73:ad:25:52:7e:fb:45:5d:75:23:b7:45:63:75:0d:
92:a4:6f:1f:b1:ae:fa:a4:12:61:91:54:d4:f6:52:4e:de:67:
05:25:c7:4f:6f:fe:19:a5:43:f5:b7:4a:f7:f9:5f:17:ab:cd:
0d:eb:ad:de:21:1f:63:da:62:dc:14:7c:77:71:bf:10:3c:fd:
07:97:d2:fc:d3:d7:57:c8:33:5c:f5:1f:06:d8:77:6d:42:19:
bf:e6:b4:e8:f3:4e:ee:dd:36:45:aa:e4:b2:43:7b:24:83:9b:
d5:69:e2:61:48:d6:c5:d6:2a:ec:f1:91:eb:2a:e2:22:d1:af:
2d:d4:73:ad:7f:6c:c2:d5:ab:ad:47:e1:05:26:cd:25:6e:42:
60:c8:d9:cb:13:d0:0d:da:e1:d1:21:a6:d9:a8:80:51:34:2e:
c7:ef:a3:4b:ad:dc:7a:18:61:8c:05:12:bc:a8:a4:94:21:20:
8b:6b:ae:ab:95:6e:57:57:1b:ca:af:20:7f:78:c2:15:78:7d:
77:91:23:24:4e:1e:08:c5:04:6a:68:77:37:02:1c:d9:36:e5:
e0:2f:8a:6a:b5:4d:c6:01:6f:3c:bf:3e:36:69:dc:f1:a5:60:
1c:84:ae:57:1c:5c:53:3d:bc:43:4f:ff:23:c5:59:ad:cb:32:
c3:46:f8:4f:b5:f9:7b:14:51:70:49:34:6d:6f:c2:cd:7f:93:
aa:b8:e4:dc:f7:a9:e8:52:af:40:fd:62:5d:5e:56:22:87:28:
74:6a:0c:98:e0:61:86:28:4d:8d:93:96:ba:06:9a:42:99:38:
d4:f0:94:a8:c9:0e:9c:ec:97:99:0f:1b:2c:8e:c4:ff:0b:c1:
56:90:ca:8c:a4:1e:09:16:d4:02:40:e6:16:04:47:a1:3f:23:
62:46:84:78:8e:37:1b:69:16:41:39:4f:00:23:58:ea:ca:6c:
69:b2:83:c3:9e:f4:8f:c8:33:1d:44:e7:90:4b:14:4c:84:8c:
ff:5f:e5:9d:3a:4c:57:79:9e:db:85:44:0c:e9:54:14:42:c1:
a7:f9:17:c7:74:00:03:4c:4e:e4:8a:47:75:a2:0c:9e:c7:ba:
f2:85:48:4f:d9:19:3c:17
```
# Encrypt Secret
```
➜ kubeseal < k3s/03-secret.yaml --cert cert.pem -o yaml > k3s/04-sealed-secret.yaml
```
04-sealed-secret.yaml
```
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
creationTimestamp: null
name: credentials
namespace: foo
spec:
encryptedData:
token: AgB46venfU8xaT2KA+1FstQApxf51r9DnGF33ZXkewaeaPg6KckWCEtaZ6sfcILPbpGZRmMW29R5lWF0HLzbnWB3ZmhouUjibWqEfeskVpCmsKntXNHI0h//8sLwoECgqreDaU34WjMGJzMIjdWZXGbym57OqJqwDGTBxBQJG2lwrRQ1EjS57juhnYuNm0V7HPEPDKCfUUhhwfqZ+GMrAJVK1JWPzztQEJY0RVeUw1AzL6PTK8HBHMSSl680ZNwC+IAZUBM36vIxHbnehbm9yB4QAeceqMMQDp8tPaK5Qw+440hYm2OdfX9+Y5ePNmXyN1h6XWMmUWUToneZk/5yTn9o9hnDelznmGl3DslAi4lzCTew56eagikXQGZE9IDpoYv1ptKTMNYjdESYSdynMTHjZYiNM5dXpCRwWxXwmuMQU3NLlmEaOupUPeNSavewoU6NvVm1Cq+DBv7SSSMQUjvHgBSFNDLRpBh3egvOqp2RKXyUq/1OCByHwlhg/HW0ZpzATUHrTDa4aRDgnaEwo+vazrOtPKlSHSop57daF7+Xx54bxguXzHQAgCBk6prqEQSuMRNOgCknuxNnFaNSYBgdsmrxTyreNwCXhAYzGja6LGSibXP843ZS3Ph1YfDtFGIzbXqB8bxd5Pbx1N0tJCIGrqIs1MoB94hdmCYWH+qe8tFZ2VgrLjOPWzQzn9EH+++ZQWLSnKQyzZyyRR4gArDnXXt3cCn3
template:
metadata:
creationTimestamp: null
name: credentials
namespace: foo
type: Opaque
```
```
➜ kubectl apply -f k3s/04-sealed-secret.yaml
sealedsecret.bitnami.com/credentials created
```
If you update credentials in sealedsecrets, it will also update that in secrets.
```
➜ kubectl get sealedsecrets -n foo
NAME AGE
credentials 40s
```
```
➜ kubectl get secrets -n foo
NAME TYPE DATA AGE
default-token-4g77w kubernetes.io/service-account-token 3 35m
credentials Opaque 1 27m
```
```
➜ kubectl get secrets credentials -o yaml -n foo
```
```
apiVersion: v1
data:
token: c2VhbGVkLXNlY3JldHMtZXhhbXBsZQ==
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","data":{"token":"c2VhbGVkLXNlY3JldHMtZXhhbXBsZQ=="},"kind":"Secret","metadata":{"annotations":{},"name":"credentials","namespace":"foo"},"type":"Opaque"}
creationTimestamp: "2021-02-15T04:43:23Z"
name: credentials
namespace: foo
resourceVersion: "1925"
selfLink: /api/v1/namespaces/foo/secrets/credentials
uid: b80b9465-d35b-422e-8ab4-6cd73d3be5b3
type: Opaque
```
To decode the token
```
➜ echo "c2VhbGVkLXNlY3JldHMtZXhhbXBsZQ==" | base64 -d
sealed-secrets-example
```
# Create an Express application
server.js
```js
'use strict';
const express = require('express');
const PORT = 8080;
const HOST = '0.0.0.0';
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);
console.log(`The Token is ${process.env.TOKEN}`);
```
Dockerfile
```
FROM node:14
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./
RUN npm install
# If you are building your code for production
# RUN npm ci --only=production
# Bundle app source
COPY . .
EXPOSE 8080
CMD [ "node", "server.js" ]
```
.dockerignore
```
node_modules
npm-debug.log
```
Build the image
```
➜ docker build -t wingkwong/sealed-secrets-example .
```
Your image will be listed by Docker
```
➜ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
wingkwong/sealed-secrets-example latest a7710ac9878f 2 minutes ago 946MB
```
Run the image
```
➜ docker run -p 8080:8080 -d wingkwong/sealed-secrets-example
1b59a182529ab9b6022eae20b1c3cc9f8c97f25e133334158f3cdf2b97d6046f
```
```
➜ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1b59a182529a wingkwong/sealed-secrets-example "docker-entrypoint.s…" 24 seconds ago Up 20 seconds 0.0.0.0:8080->8080/tcp unruffled_boyd
```
``<token>`` is undefined as we don't define it in environment.
```
➜ docker logs 1b59a182529a
Running on http://0.0.0.0:8080
The Token is undefined
```
Push to Docker Hub
```
➜ docker push wingkwong/sealed-secrets-example
The push refers to repository [docker.io/wingkwong/sealed-secrets-example]
9c504e9b67e2: Pushed
9443efda2621: Pushed
4f5d94c4d9a0: Pushed
c190d83c7139: Pushed
7ad435f34cd1: Mounted from library/node
c52fdd5ebc39: Mounted from library/node
5faa7f35f547: Mounted from library/node
9b88fe065b35: Mounted from library/node
4ca605ea46de: Mounted from library/node
601f04850201: Mounted from library/node
846bd2f3b216: Mounted from library/node
2b3e667f5e92: Mounted from library/node
e891be0c59b2: Mounted from library/node
latest: digest: sha256:0af214e064458380d4a5ea740176c7312e9bcf638b8aaa207b401bb9e64ea35c size: 3047
```
# Deploy an Express application to test sealed-secrets
05-deployment.yaml
```
apiVersion: apps/v1
kind: Deployment
metadata:
name: sealed-secrets-example-deployment
namespace: foo
spec:
replicas: 1
selector:
matchLabels:
app: sealed-secrets-example
template:
metadata:
labels: # labels to select/identify the deployment
app: sealed-secrets-example
spec: # pod spec
containers:
- name: sealed-secrets-example
image: wingkwong/sealed-secrets-example:latest # image we pushed
ports:
- containerPort: 8080
env:
- name: TOKEN
valueFrom:
secretKeyRef:
key: token
name: credentials
```
```
➜ kubectl apply -f k3s/05-deployment.yaml
deployment.apps/sealed-secrets-example-deployment created
```
```
➜ kubectl get pods -n foo
NAME READY STATUS RESTARTS AGE
sealed-secrets-example-deployment-6bb786499c-2rbtq 1/1 Running 0 9m24s
```
```
➜ kubectl describe pods sealed-secrets-example-deployment-6bb786499c-2rbtq -n foo
Normal Pulling 6m30s kubelet, k3d-sealed-secrets-example-server Pulling image "wingkwong/sealed-secrets-example:latest"
Normal Pulled 43s kubelet, k3d-sealed-secrets-example-server Successfully pulled image "wingkwong/sealed-secrets-example:lates
```
```
➜ kubectl logs -l app=sealed-secrets-example -n foo
Running on http://0.0.0.0:8080
The Token is sealed-secrets-example
```
# Clean up
```
k3d delete -n sealed-secrets-example
```
# References
- ["Sealed Secrets" for Kubernetes](https://github.com/bitnami-labs/sealed-secrets)
Subscribe to:
Posts (Atom)
A Fun Problem - Math
# Problem Statement JATC's math teacher always gives the class some interesting math problems so that they don't get bored. Today t...
-
SHA stands for Secure Hashing Algorithm and 2 is just a version number. SHA-2 revises the construction and the big-length of the signature f...
-
Contest Link: [https://www.e-olymp.com/en/contests/19775](https://www.e-olymp.com/en/contests/19775) Full Solution: [https://github.com/...