Processing math: 100%

Sunday, 28 February 2021

Chinese Remainder Theorem

A linear congruence can be displayed as

axb(mod m)

By definition of congruence, axb(mod m) iff axb 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.

x2(mod 3) x3(mod 5) x2(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+105n

where

n0,1,2,3,

Given a set of congruence equations, we are interested to find a that produces the given remainders.

aa1(mod p1)

aa2(mod p2)

 

aak(mod pk)

where every pair pi are pairwise coprime, ai are given constants.

Problem: Oversleeping

In this problem, we are interested in finding the minimum non-negative integer t such that

Xt mod (2X+2Y)<X+Y

Pt mod (P+Q)<P+Q

We can solve this problem using Chinese Remainder Theorem.

tt1(mod 2X+2Y) tt2(mod P+Q)

AtCoder has provided a crt library here, which makes the implementation relatively simple.

#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.

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.

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 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.

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 <token> 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

'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

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...