Compare commits

...

24 commits

Author SHA1 Message Date
a79a37d4d4 Merge pull request 'rate-limit' (#3) from rate-limit into main
Limiting the rates

Introducing rate limiting seemed like a very sensible step in order to mitigate against some forms of DoS attacks. As of now, we set the rates to a fixed amount with no configuration ability. This might change later on, depending on the use cases.
2024-01-23 09:02:06 +00:00
fba2a495e2 Merge branch 'main' into rate-limit 2024-01-23 09:00:30 +00:00
bba058afa0 [Skip-CI] Remove keywords from valid config 2024-01-19 11:40:08 +01:00
12034502ac Use default values in tests 2024-01-19 11:39:42 +01:00
4881ea3c0d Refactor Keywords 2024-01-19 11:38:33 +01:00
38183f7bf1 [Skip-CI, WIP] Refactor middleware generation 2024-01-19 10:18:49 +01:00
62fb2a37a0 [WIP] Use defaults for rate limit 2024-01-19 10:14:44 +01:00
aec67352d5 [Skip-CI] Add ToDos 2024-01-19 09:55:00 +01:00
3f0de27055 Add Middleware to be skipped 2024-01-17 15:40:47 +01:00
7d21f5aff1 Fix test 2024-01-17 12:44:22 +01:00
260d086232 Further split flow control 2024-01-17 12:36:24 +01:00
56b843981f Correct api version 2024-01-17 12:35:48 +01:00
777b94a340 Add average and burst keys 2024-01-17 11:57:55 +01:00
d9cb19242b Format 2024-01-17 11:57:40 +01:00
010ab3d8fd Split if into multiple whens
Otherwise weird behavior.
2024-01-17 11:57:19 +01:00
054e6954af Implement tests 2024-01-17 11:43:32 +01:00
2a6b6ccf3f Implement rate limit middleware 2024-01-17 11:43:15 +01:00
13e718ca37 Implement rate limit ingress 2024-01-17 11:40:58 +01:00
52e43fe23c Add specs for rate limit options 2024-01-17 11:37:31 +01:00
a63f170ace Generate ingress with rate limit conditionally 2024-01-17 11:36:43 +01:00
220eb337f9 No default values for optional rate limiting 2024-01-17 11:35:20 +01:00
8a3194e715 Add ToDo 2024-01-16 15:50:08 +01:00
c5e777c9c5 WIP: Add defn-spec for rate-limiting ingress 2024-01-16 15:44:10 +01:00
1ed850aea2 Initial rate limit middleware 2024-01-16 15:18:18 +01:00
5 changed files with 63 additions and 5 deletions

View file

@ -56,7 +56,7 @@ def test_schema(project):
"java -jar target/uberjar/c4k-forgejo-standalone.jar "
+ "src/test/resources/forgejo-test/valid-config.yaml "
+ "src/test/resources/forgejo-test/valid-auth.yaml | "
+ "kubeconform --kubernetes-version 1.23.0 --strict --skip Certificate -",
+ """kubeconform --kubernetes-version 1.23.0 --strict --skip "Certificate, Middleware" -""",
shell=True,
check=True,
)

View file

@ -9,6 +9,7 @@
[dda.c4k-common.postgres :as postgres]))
(def config-defaults {:issuer "staging", :deploy-federated "false"})
(def rate-limit-defaults {:max-rate 10, :max-concurrent-requests 5})
(def config? (s/keys :req-un [::forgejo/fqdn
::forgejo/mailer-from
@ -30,7 +31,7 @@
(def vol? (s/keys :req-un [::forgejo/volume-total-storage-size]))
(defn k8s-objects [config auth]
(defn k8s-objects [config auth] ; ToDo: ADR for generate functions - vector or no vector?
(let [storage-class (if (contains? config :postgres-data-volume-path) :manual :local-path)]
(map yaml/to-string
(filter #(not (nil? %))
@ -46,11 +47,12 @@
(postgres/generate-service)
(forgejo/generate-deployment config)
(forgejo/generate-service)
(forgejo/generate-service-ssh)
(forgejo/generate-service-ssh)
(forgejo/generate-data-volume config)
(forgejo/generate-appini-env config)
(forgejo/generate-secrets auth)]
(forgejo/generate-ingress-and-cert config)
(forgejo/generate-secrets auth)
(forgejo/generate-rate-limit-middleware rate-limit-defaults)] ; this does not have a vector as output
(forgejo/generate-rate-limit-ingress-and-cert config) ; this function has a vector as output
(when (contains? config :restic-repository)
[(backup/generate-config config)
(backup/generate-secret auth)

View file

@ -42,6 +42,8 @@
(s/def ::mailer-pw pred/bash-env-string?)
(s/def ::issuer pred/letsencrypt-issuer?)
(s/def ::volume-total-storage-size (partial pred/int-gt-n? 5))
(s/def ::max-rate int?)
(s/def ::max-concurrent-requests int?)
(def config? (s/keys :req-un [::fqdn
::mailer-from
@ -53,6 +55,9 @@
::default-app-name
::service-domain-whitelist]))
(def rate-limit-config? (s/keys :req-un [::max-rate
::max-concurrent-requests]))
(def auth? (s/keys :req-un [::postgres/postgres-db-user ::postgres/postgres-db-password ::mailer-user ::mailer-pw]))
(def vol? (s/keys :req-un [::volume-total-storage-size]))
@ -119,6 +124,26 @@
:fqdns [fqdn]}
config))))
(defn-spec generate-rate-limit-ingress-and-cert pred/map-or-seq?
[config config?]
(->
(generate-ingress-and-cert config) ; returns a vector
(#(assoc-in % ; Attention: heavily relying on the output order of ing/generate-ingress-and-cert
[1 :metadata :annotations :traefik.ingress.kubernetes.io/router.middlewares]
(str
(-> (second %) :metadata :annotations :traefik.ingress.kubernetes.io/router.middlewares)
", default-ratelimit@kubernetescrd")))))
; using :average and :burst seems sensible, :period may be interesting for fine tuning later on
(defn-spec generate-rate-limit-middleware pred/map-or-seq?
[config rate-limit-config?]
(let [{:keys [max-rate max-concurrent-requests]} config]
(->
(yaml/load-as-edn "forgejo/middleware-ratelimit.yaml")
(cm/replace-key-value :average max-rate)
(cm/replace-key-value :burst max-concurrent-requests))))
(defn-spec generate-data-volume pred/map-or-seq?
[config vol?]
(let [{:keys [volume-total-storage-size]} config

View file

@ -0,0 +1,8 @@
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: ratelimit
spec:
rateLimit: # Config options for rate limiting: https://doc.traefik.io/traefik/middlewares/http/ratelimit/
average: AVG
burst: BRS

View file

@ -130,3 +130,26 @@
:storage-c2 "15Gi"}
(th/map-diff (cut/generate-data-volume {:volume-total-storage-size 1})
(cut/generate-data-volume {:volume-total-storage-size 15})))))
(deftest should-generate-middleware-ratelimit
(is (= {:apiVersion "traefik.containo.us/v1alpha1",
:kind "Middleware",
:metadata {:name "ratelimit"},
:spec {:rateLimit {:average 10, :burst 5}}}
(cut/generate-rate-limit-middleware {:max-rate 10, :max-concurrent-requests 5}))))
(deftest should-generate-middleware-ratelimit-ingress-and-cert
(is (= {:traefik.ingress.kubernetes.io/router.entrypoints "web, websecure",
:traefik.ingress.kubernetes.io/router.middlewares
"default-redirect-https@kubernetescrd, default-ratelimit@kubernetescrd",
:metallb.universe.tf/address-pool "public"}
(-> (second
(cut/generate-rate-limit-ingress-and-cert
{:fqdn "test.de"
:mailer-from ""
:mailer-host "m.t.de"
:mailer-port "123"
:service-noreply-address ""
:average 10
:burst 5}))
:metadata :annotations))))