ce7cb702218693d08ea6d83464d2457c9250027c
This commit is contained in:
commit
34c5f8963c
13 changed files with 145336 additions and 0 deletions
165
scripts/hooks/hook-tests.fsx
Normal file
165
scripts/hooks/hook-tests.fsx
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
open System
|
||||
open System.Diagnostics
|
||||
open System.IO
|
||||
|
||||
type Result = { Code: int; Output: string; Error: string }
|
||||
type Fixture = { Root: string; Source: string; Mask: string }
|
||||
|
||||
let require condition message =
|
||||
if not condition then invalidOp message
|
||||
|
||||
let run root environment executable arguments =
|
||||
let start = ProcessStartInfo executable
|
||||
start.WorkingDirectory <- root
|
||||
start.UseShellExecute <- false
|
||||
start.RedirectStandardOutput <- true
|
||||
start.RedirectStandardError <- true
|
||||
for argument in arguments do start.ArgumentList.Add argument
|
||||
for name, value in environment do start.Environment[name] <- value
|
||||
use child = Process.Start start
|
||||
let output = child.StandardOutput.ReadToEndAsync()
|
||||
let error = child.StandardError.ReadToEndAsync()
|
||||
child.WaitForExit()
|
||||
{ Code = child.ExitCode; Output = output.Result; Error = error.Result }
|
||||
|
||||
let git fixture arguments =
|
||||
let result = run fixture.Root [] "git" arguments
|
||||
require (result.Code = 0) result.Error
|
||||
result.Output
|
||||
|
||||
let write path (text: string) = File.WriteAllText(path, text)
|
||||
let stage fixture = git fixture [ "add"; "." ] |> ignore
|
||||
let hook = Path.Combine(__SOURCE_DIRECTORY__, "pre-commit")
|
||||
|
||||
let runHook fixture environment =
|
||||
let before = git fixture [ "ls-files"; "--stage"; "-z" ]
|
||||
let result = run fixture.Root environment hook []
|
||||
require (before = git fixture [ "ls-files"; "--stage"; "-z" ]) "hook changed the index"
|
||||
result
|
||||
|
||||
let passes fixture =
|
||||
let result = runHook fixture []
|
||||
require (result.Code = 0) result.Error
|
||||
|
||||
let fails expected fixture =
|
||||
let result = runHook fixture []
|
||||
require (result.Code <> 0) "hook unexpectedly succeeded"
|
||||
require (result.Error.Contains(expected: string)) result.Error
|
||||
|
||||
let directory fixture path = Directory.CreateDirectory(Path.Combine(fixture.Root, path)).FullName
|
||||
|
||||
let tests: (string * (Fixture -> unit)) list =
|
||||
[ "staged tree", fun fixture ->
|
||||
write fixture.Source "unstaged source edit\n"
|
||||
write fixture.Mask "unstaged invalid mask\n"
|
||||
passes fixture
|
||||
|
||||
"unrelated change", fun fixture ->
|
||||
write fixture.Source "other=changed\nvalue=synthetic\n"
|
||||
stage fixture
|
||||
passes fixture
|
||||
|
||||
"missing match", fun fixture ->
|
||||
write fixture.Source "value=changed\n"
|
||||
stage fixture
|
||||
fails "no match" fixture
|
||||
|
||||
"multiple matches", fun fixture ->
|
||||
write fixture.Source "synthetic synthetic\n"
|
||||
stage fixture
|
||||
fails "multiple matches" fixture
|
||||
|
||||
"overlapping matches", fun fixture ->
|
||||
write fixture.Source "aaa"
|
||||
write fixture.Mask "[[replace]]\nbefore = 'aa'\nafter = 'b'\n"
|
||||
stage fixture
|
||||
fails "multiple matches" fixture
|
||||
|
||||
"empty before", fun fixture ->
|
||||
write fixture.Mask "[[replace]]\nbefore = ''\nafter = 'x'\n"
|
||||
stage fixture
|
||||
fails "before is empty" fixture
|
||||
|
||||
"ordered rules", fun fixture ->
|
||||
write fixture.Mask
|
||||
("[[replace]]\nbefore = 'synthetic'\nafter = 'intermediate'\n"
|
||||
+ "[[replace]]\nbefore = 'intermediate'\nafter = '********'\n")
|
||||
stage fixture
|
||||
passes fixture
|
||||
|
||||
"invalid TOML", fun fixture ->
|
||||
write fixture.Mask "invalid = ["
|
||||
stage fixture
|
||||
let result = runHook fixture []
|
||||
require (result.Code <> 0) "invalid TOML was accepted"
|
||||
|
||||
"invalid schema", fun fixture ->
|
||||
write fixture.Mask "[[replace]]\nbefore = 'synthetic'\nafter = 1\n"
|
||||
stage fixture
|
||||
fails "expected text" fixture
|
||||
|
||||
"missing target", fun fixture ->
|
||||
git fixture [ "rm"; "--cached"; "config.txt" ] |> ignore
|
||||
fails "target is not a regular file" fixture
|
||||
|
||||
"symlink target", fun fixture ->
|
||||
File.Delete fixture.Source
|
||||
File.CreateSymbolicLink(fixture.Source, "elsewhere") |> ignore
|
||||
stage fixture
|
||||
fails "target is not a regular file" fixture
|
||||
|
||||
"omitted subtree", fun fixture ->
|
||||
let hidden = directory fixture "hidden"
|
||||
write (Path.Combine(hidden, ".omit")) ""
|
||||
write (Path.Combine(hidden, "invalid.mask.toml")) "invalid"
|
||||
let nested = directory fixture "hidden/nested"
|
||||
write (Path.Combine(nested, ".omit")) ""
|
||||
write (Path.Combine(nested, "legacy.mask.diff")) "invalid"
|
||||
stage fixture
|
||||
let result = runHook fixture []
|
||||
require (result.Code = 0) result.Error
|
||||
require (result.Output.Contains "1 directories omitted") result.Output
|
||||
|
||||
"omit prefix boundary", fun fixture ->
|
||||
let hidden = directory fixture "hidden"
|
||||
write (Path.Combine(hidden, ".omit")) ""
|
||||
let peer = directory fixture "hidden-peer"
|
||||
write (Path.Combine(peer, "invalid.mask.toml")) "invalid"
|
||||
stage fixture
|
||||
fails "target is not a regular file" fixture
|
||||
|
||||
"unstaged omit", fun fixture ->
|
||||
write fixture.Source "synthetic synthetic"
|
||||
stage fixture
|
||||
write (Path.Combine(fixture.Root, ".omit")) ""
|
||||
fails "multiple matches" fixture
|
||||
|
||||
"legacy format", fun fixture ->
|
||||
write (Path.Combine(fixture.Root, "old.mask.diff")) "invalid"
|
||||
stage fixture
|
||||
fails "legacy mask format" fixture
|
||||
|
||||
"alternate index", fun fixture ->
|
||||
let index = Path.Combine(fixture.Root, "alternate")
|
||||
File.Copy(Path.Combine(fixture.Root, ".git/index"), index)
|
||||
write fixture.Source "staged drift\n"
|
||||
git fixture [ "add"; "config.txt" ] |> ignore
|
||||
let before = File.ReadAllBytes index
|
||||
let result = runHook fixture [ "GIT_INDEX_FILE", index ]
|
||||
require (result.Code = 0) result.Error
|
||||
require (before = File.ReadAllBytes index) "hook changed the alternate index" ]
|
||||
|
||||
for name, test in tests do
|
||||
let root = Directory.CreateDirectory(Path.Combine(fsi.CommandLineArgs[1], $"hook-tests-{Guid.NewGuid():N}")).FullName
|
||||
let fixture = { Root = root; Source = Path.Combine(root, "config.txt"); Mask = Path.Combine(root, "config.txt.mask.toml") }
|
||||
try
|
||||
git fixture [ "init"; "-q" ] |> ignore
|
||||
write fixture.Source "value=synthetic\n"
|
||||
write fixture.Mask "[[replace]]\nbefore = 'synthetic'\nafter = '********'\n"
|
||||
stage fixture
|
||||
test fixture
|
||||
printfn "passed: %s" name
|
||||
finally
|
||||
Directory.Delete(root, true)
|
||||
|
||||
printfn "%d hook tests passed" tests.Length
|
||||
2
scripts/hooks/pre-commit
Executable file
2
scripts/hooks/pre-commit
Executable file
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
exec dotnet fsi --quiet --exec "$(dirname "$0")/pre-commit.fsx" "$@"
|
||||
30
scripts/hooks/pre-commit.fsx
Normal file
30
scripts/hooks/pre-commit.fsx
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#r "nuget: Tomlyn, 2.10.1"
|
||||
#load "../../services/project-delivery/actions/masking.fsx"
|
||||
|
||||
open System
|
||||
|
||||
let checkIndex () =
|
||||
let git arguments = Masking.run "git" arguments None
|
||||
|
||||
let entries =
|
||||
git [ "ls-files"; "--stage"; "-z" ]
|
||||
|> _.Split('\u0000', StringSplitOptions.RemoveEmptyEntries)
|
||||
|> Array.map (fun entry ->
|
||||
let fields = entry.Split('\t', 2)
|
||||
let metadata = fields[0].Split(' ')
|
||||
|
||||
if metadata[2] <> "0" then
|
||||
invalidOp "unmerged index"
|
||||
|
||||
fields[1], (metadata[0] = "100644" || metadata[0] = "100755", metadata[1]))
|
||||
|> Map.ofArray
|
||||
|
||||
Masking.makePlan Masking.parseRules (entries |> Map.map (fun _ (regular, _) -> regular)) (fun path ->
|
||||
git [ "cat-file"; "blob"; snd entries[path] ])
|
||||
|
||||
try
|
||||
let plan = checkIndex ()
|
||||
printfn "masks: %d staged masks verified; %d directories omitted" plan.Masks.Length plan.Omitted.Length
|
||||
with :? InvalidOperationException as error ->
|
||||
eprintfn "masks: %s" error.Message
|
||||
exit 1
|
||||
7
scripts/k3s/config.agent-nas.yaml
Normal file
7
scripts/k3s/config.agent-nas.yaml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
server: https://k3s.ms2k.internal:6443
|
||||
|
||||
kubelet-arg:
|
||||
- max-pods=250
|
||||
|
||||
node-taint:
|
||||
- workload=nas:PreferNoSchedule
|
||||
23
scripts/k3s/config.server.yaml
Normal file
23
scripts/k3s/config.server.yaml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
server: https://********
|
||||
|
||||
flannel-backend: none
|
||||
disable-network-policy: true
|
||||
disable-kube-proxy: true
|
||||
|
||||
tls-san:
|
||||
- "********"
|
||||
- 10.72.123.235
|
||||
|
||||
cluster-cidr: 172.19.28.14/12
|
||||
service-cidr: 10.74.150.93/12
|
||||
cluster-dns: 10.97.104.110
|
||||
|
||||
secrets-encryption: true
|
||||
|
||||
kubelet-arg:
|
||||
- max-pods=250
|
||||
|
||||
disable:
|
||||
- coredns
|
||||
- traefik
|
||||
- servicelb
|
||||
74
scripts/k3s/install.sh
Executable file
74
scripts/k3s/install.sh
Executable file
|
|
@ -0,0 +1,74 @@
|
|||
#!/usr/bin/env bash
|
||||
# Usage: install.sh server|agent <ssh-target>
|
||||
set -euo pipefail
|
||||
set +o xtrace 2>/dev/null || true
|
||||
|
||||
VAULT_PATH="${K3S_VAULT_PATH:-secret/k3s}"
|
||||
VAULT_FIELD="${K3S_VAULT_FIELD:-server-token}"
|
||||
INSTALL_K3S_VERSION="${INSTALL_K3S_VERSION:-v1.36.2+k3s1}"
|
||||
REMOTE_CONFIG=/etc/rancher/k3s/config.yaml
|
||||
|
||||
die() { echo "error: $*" >&2; exit 1; }
|
||||
|
||||
usage() {
|
||||
cat >&2 <<'EOF'
|
||||
Usage: install.sh server|agent <ssh-target>
|
||||
EOF
|
||||
exit 2
|
||||
}
|
||||
|
||||
scrub() {
|
||||
token=''
|
||||
unset token 2>/dev/null || true
|
||||
}
|
||||
|
||||
trap scrub EXIT
|
||||
|
||||
[[ $# -eq 2 ]] || usage
|
||||
role=$1
|
||||
target=$2
|
||||
|
||||
case "$role" in
|
||||
server|agent) ;;
|
||||
*) die "role must be server or agent (got: $role)" ;;
|
||||
esac
|
||||
[[ -n "$target" ]] || die "ssh-target is empty"
|
||||
|
||||
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
|
||||
case "$role" in
|
||||
server) config=$script_dir/config.server.yaml ;;
|
||||
agent) config=$script_dir/config.agent-nas.yaml ;;
|
||||
esac
|
||||
[[ -f "$config" ]] || die "missing config: $config"
|
||||
|
||||
if grep -qE '^[[:space:]]*token:[[:space:]]' "$config"; then
|
||||
die "config must not contain token: ($config)"
|
||||
fi
|
||||
|
||||
command -v vault >/dev/null || die "vault CLI not found"
|
||||
command -v ssh >/dev/null || die "ssh not found"
|
||||
command -v scp >/dev/null || die "scp not found"
|
||||
|
||||
token=$(vault kv get -field="$VAULT_FIELD" "$VAULT_PATH") \
|
||||
|| die "failed to read $VAULT_FIELD from $VAULT_PATH"
|
||||
[[ -n "$token" ]] || die "empty token from $VAULT_PATH field $VAULT_FIELD"
|
||||
|
||||
echo "role=$role target=$target config=$config version=$INSTALL_K3S_VERSION"
|
||||
|
||||
ssh -o BatchMode=yes "$target" "install -d -m 0755 /etc/rancher/k3s"
|
||||
scp -o BatchMode=yes -q "$config" "${target}:/tmp/k3s-config.yaml"
|
||||
ssh -o BatchMode=yes "$target" "install -m 0600 /tmp/k3s-config.yaml $REMOTE_CONFIG && rm -f /tmp/k3s-config.yaml"
|
||||
|
||||
# K3S_TOKEN must not appear in ssh/remote argv (visible in ps).
|
||||
ssh -o BatchMode=yes "$target" 'bash -s' <<EOF
|
||||
set -euo pipefail
|
||||
set +o xtrace 2>/dev/null || true
|
||||
export INSTALL_K3S_VERSION=$(printf '%q' "$INSTALL_K3S_VERSION")
|
||||
export K3S_TOKEN=$(printf '%q' "$token")
|
||||
curl -sfL https://get.k3s.io | sh -s - $(printf '%q' "$role")
|
||||
unset K3S_TOKEN
|
||||
EOF
|
||||
|
||||
scrub
|
||||
echo "install finished on $target ($role)"
|
||||
234
scripts/k3s/prepare-node.sh
Executable file
234
scripts/k3s/prepare-node.sh
Executable file
|
|
@ -0,0 +1,234 @@
|
|||
#!/usr/bin/env bash
|
||||
# Usage: prepare-node.sh [--defer-restart] <ssh-target>
|
||||
# Host packages, Longhorn dir, runsc, internal CA + registries.yaml. Idempotent; before install.sh.
|
||||
set -euo pipefail
|
||||
|
||||
CA_URL="${K3S_CA_URL:-https://vault.quorate.internal/v1/pki/ca/pem}"
|
||||
CA_REMOTE=/etc/rancher/k3s/quorate-internal-ca.crt
|
||||
REG_REMOTE=/etc/rancher/k3s/registries.yaml
|
||||
|
||||
die() { echo "error: $*" >&2; exit 1; }
|
||||
|
||||
usage() {
|
||||
cat >&2 <<'EOF'
|
||||
Usage: prepare-node.sh [--defer-restart] <ssh-target>
|
||||
EOF
|
||||
exit 2
|
||||
}
|
||||
|
||||
defer_restart=0
|
||||
if [[ ${1:-} == --defer-restart ]]; then
|
||||
defer_restart=1
|
||||
shift
|
||||
fi
|
||||
|
||||
[[ $# -eq 1 ]] || usage
|
||||
target=$1
|
||||
[[ -n "$target" ]] || die "ssh-target is empty"
|
||||
|
||||
command -v ssh >/dev/null || die "ssh not found"
|
||||
command -v scp >/dev/null || die "scp not found"
|
||||
command -v curl >/dev/null || die "curl not found"
|
||||
command -v openssl >/dev/null || die "openssl not found"
|
||||
|
||||
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
registries_src=$script_dir/registries.yaml
|
||||
[[ -f $registries_src ]] || die "missing $registries_src"
|
||||
|
||||
workdir=$(mktemp -d)
|
||||
trap 'rm -rf "$workdir"' EXIT
|
||||
ca_local=$workdir/quorate-internal-ca.crt
|
||||
|
||||
curl -fsSL --max-time 30 "$CA_URL" -o "$ca_local" \
|
||||
|| die "failed to fetch CA from $CA_URL"
|
||||
openssl x509 -in "$ca_local" -noout 2>/dev/null \
|
||||
|| die "fetched CA is not a valid PEM certificate"
|
||||
openssl x509 -in "$ca_local" -noout -text | grep -q 'CA:TRUE' \
|
||||
|| die "fetched certificate is not a CA"
|
||||
|
||||
echo "prepare-node target=$target"
|
||||
|
||||
ssh -o BatchMode=yes "$target" "install -d -m 0755 /etc/rancher/k3s"
|
||||
scp -o BatchMode=yes -q "$ca_local" "${target}:/tmp/quorate-internal-ca.crt"
|
||||
scp -o BatchMode=yes -q "$registries_src" "${target}:/tmp/k3s-registries.yaml"
|
||||
|
||||
ssh -o BatchMode=yes "$target" "bash -s -- $defer_restart" <<'REMOTE'
|
||||
set -euo pipefail
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
defer_restart=$1
|
||||
|
||||
if ! command -v apt-get >/dev/null; then
|
||||
echo "error: only Debian-family apt hosts are supported" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pkg_installed() {
|
||||
dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -q 'install ok installed'
|
||||
}
|
||||
|
||||
need_k3s_restart=0
|
||||
|
||||
pkgs=(open-iscsi nfs-common xfsprogs smartmontools)
|
||||
missing=()
|
||||
for p in "${pkgs[@]}"; do
|
||||
pkg_installed "$p" || missing+=("$p")
|
||||
done
|
||||
if ((${#missing[@]})); then
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq "${missing[@]}"
|
||||
fi
|
||||
|
||||
if systemctl cat iscsid.service >/dev/null 2>&1; then
|
||||
systemctl is-enabled --quiet iscsid 2>/dev/null || systemctl enable iscsid >/dev/null
|
||||
systemctl is-active --quiet iscsid 2>/dev/null || systemctl start iscsid
|
||||
fi
|
||||
|
||||
install -d -m 0755 /var/lib/longhorn
|
||||
|
||||
inotify_file=/etc/sysctl.d/90-k3s-inotify.conf
|
||||
inotify_limit=1024
|
||||
inotify_setting="fs.inotify.max_user_instances = $inotify_limit"
|
||||
install -d -m 0755 /etc/sysctl.d
|
||||
if [[ ! -f $inotify_file ]] || ! cmp -s <(printf '%s\n' "$inotify_setting") "$inotify_file"; then
|
||||
printf '%s\n' "$inotify_setting" >"$inotify_file"
|
||||
fi
|
||||
chmod 0644 "$inotify_file"
|
||||
if [[ $(sysctl -n fs.inotify.max_user_instances) != "$inotify_limit" ]]; then
|
||||
sysctl -p "$inotify_file"
|
||||
fi
|
||||
|
||||
CA_REMOTE=/etc/rancher/k3s/quorate-internal-ca.crt
|
||||
REG_REMOTE=/etc/rancher/k3s/registries.yaml
|
||||
SYS_CA=/usr/local/share/ca-certificates/internal-root-ca.crt
|
||||
|
||||
install -d -m 0755 /etc/rancher/k3s
|
||||
if [[ -f $CA_REMOTE ]] && cmp -s /tmp/quorate-internal-ca.crt "$CA_REMOTE"; then
|
||||
:
|
||||
else
|
||||
install -m 0644 /tmp/quorate-internal-ca.crt "$CA_REMOTE"
|
||||
need_k3s_restart=1
|
||||
fi
|
||||
|
||||
if [[ -f $REG_REMOTE ]] && cmp -s /tmp/k3s-registries.yaml "$REG_REMOTE"; then
|
||||
:
|
||||
else
|
||||
install -m 0644 /tmp/k3s-registries.yaml "$REG_REMOTE"
|
||||
need_k3s_restart=1
|
||||
fi
|
||||
|
||||
if [[ -f $SYS_CA ]] && cmp -s /tmp/quorate-internal-ca.crt "$SYS_CA"; then
|
||||
:
|
||||
else
|
||||
install -d -m 0755 /usr/local/share/ca-certificates
|
||||
install -m 0644 /tmp/quorate-internal-ca.crt "$SYS_CA"
|
||||
update-ca-certificates >/dev/null
|
||||
fi
|
||||
rm -f /tmp/quorate-internal-ca.crt /tmp/k3s-registries.yaml
|
||||
|
||||
if ! command -v runsc >/dev/null 2>&1 || ! command -v containerd-shim-runsc-v1 >/dev/null 2>&1; then
|
||||
for p in ca-certificates curl gnupg; do
|
||||
pkg_installed "$p" || { apt-get update -qq; apt-get install -y -qq ca-certificates curl gnupg; break; }
|
||||
done
|
||||
|
||||
if [[ ! -f /usr/share/keyrings/gvisor-archive-keyring.gpg ]]; then
|
||||
curl -fsSL https://gvisor.dev/archive.key | gpg --dearmor -o /usr/share/keyrings/gvisor-archive-keyring.gpg
|
||||
fi
|
||||
|
||||
arch=$(dpkg --print-architecture)
|
||||
gvisor_list=/etc/apt/sources.list.d/gvisor.list
|
||||
gvisor_line="deb [arch=${arch} signed-by=/usr/share/keyrings/gvisor-archive-keyring.gpg] https://storage.googleapis.com/gvisor/releases release main"
|
||||
if [[ ! -f $gvisor_list ]] || ! grep -qxF "$gvisor_line" "$gvisor_list"; then
|
||||
printf '%s\n' "$gvisor_line" >"$gvisor_list"
|
||||
fi
|
||||
|
||||
if ! { apt-get update -qq && apt-get install -y -qq runsc \
|
||||
&& command -v runsc >/dev/null && command -v containerd-shim-runsc-v1 >/dev/null; }; then
|
||||
ARCH=$(uname -m)
|
||||
URL=https://storage.googleapis.com/gvisor/releases/release/latest/${ARCH}
|
||||
tmp=$(mktemp -d)
|
||||
curl -fsSL -o "$tmp/gvisor.tar.bz2" "${URL}/gvisor.tar.bz2"
|
||||
curl -fsSL -o "$tmp/gvisor.tar.bz2.sha512" "${URL}/gvisor.tar.bz2.sha512"
|
||||
(cd "$tmp" && sha512sum -c gvisor.tar.bz2.sha512)
|
||||
tar -xjf "$tmp/gvisor.tar.bz2" -C /usr/local/bin
|
||||
rm -rf "$tmp"
|
||||
fi
|
||||
need_k3s_restart=1
|
||||
fi
|
||||
|
||||
command -v runsc >/dev/null || { echo "error: runsc not on PATH" >&2; exit 1; }
|
||||
command -v containerd-shim-runsc-v1 >/dev/null || {
|
||||
echo "error: containerd-shim-runsc-v1 not on PATH" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
ctd_dir=/var/lib/rancher/k3s/agent/etc/containerd
|
||||
tmpl=$ctd_dir/config-v3.toml.tmpl
|
||||
read -r -d '' desired_tmpl <<'TMPL' || true
|
||||
{{ template "base" . }}
|
||||
|
||||
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"
|
||||
pod_annotations = ["dev.gvisor.spec.mount.var-run-argo.share", "dev.gvisor.spec.mount.var-run-argo.type", "dev.gvisor.spec.mount.var-run-argo.options"]
|
||||
|
||||
[plugins.'io.containerd.nri.v1.nri']
|
||||
disable = false
|
||||
disable_connections = false
|
||||
plugin_config_path = "/etc/nri/conf.d"
|
||||
plugin_path = "/opt/nri/plugins"
|
||||
plugin_registration_timeout = "5s"
|
||||
plugin_request_timeout = "2s"
|
||||
socket_path = "/var/run/nri/nri.sock"
|
||||
TMPL
|
||||
|
||||
mkdir -p "$ctd_dir"
|
||||
if [[ -f $tmpl ]] && cmp -s <(printf '%s\n' "$desired_tmpl") "$tmpl"; then
|
||||
:
|
||||
else
|
||||
printf '%s\n' "$desired_tmpl" >"$tmpl"
|
||||
chmod 644 "$tmpl"
|
||||
need_k3s_restart=1
|
||||
fi
|
||||
|
||||
if [[ -f $ctd_dir/config.toml ]]; then
|
||||
grep -q 'runtimes.runsc' "$ctd_dir/config.toml" || need_k3s_restart=1
|
||||
grep -q 'io.containerd.nri.v1.nri' "$ctd_dir/config.toml" || need_k3s_restart=1
|
||||
fi
|
||||
|
||||
k3s_unit=
|
||||
if systemctl is-active --quiet k3s 2>/dev/null || systemctl is-enabled --quiet k3s 2>/dev/null; then
|
||||
k3s_unit=k3s
|
||||
elif systemctl is-active --quiet k3s-agent 2>/dev/null || systemctl is-enabled --quiet k3s-agent 2>/dev/null; then
|
||||
k3s_unit=k3s-agent
|
||||
fi
|
||||
|
||||
if [[ $need_k3s_restart -eq 1 ]]; then
|
||||
if [[ $defer_restart -eq 1 ]]; then
|
||||
echo "k3s restart: deferred"
|
||||
elif [[ -n $k3s_unit ]]; then
|
||||
systemctl restart "$k3s_unit"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $defer_restart -eq 0 && -n $k3s_unit ]]; then
|
||||
grep -q 'io.containerd.nri.v1.nri' "$ctd_dir/config.toml"
|
||||
grep -q 'socket_path = "/var/run/nri/nri.sock"' "$ctd_dir/config.toml"
|
||||
for _ in {1..30}; do
|
||||
[[ -S /var/run/nri/nri.sock ]] && break
|
||||
sleep 1
|
||||
done
|
||||
[[ -S /var/run/nri/nri.sock ]] || {
|
||||
echo "error: NRI socket not available after $k3s_unit restart" >&2
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
echo "packages: ${pkgs[*]}"
|
||||
echo "longhorn: /var/lib/longhorn"
|
||||
echo "runsc: $(runsc --version 2>&1 | head -1)"
|
||||
echo "registry CA: $CA_REMOTE"
|
||||
echo "registries: $REG_REMOTE"
|
||||
echo "system CA: $SYS_CA"
|
||||
echo "prepare-node finished on $(hostname)"
|
||||
REMOTE
|
||||
|
||||
echo "prepare-node finished on $target"
|
||||
14
scripts/k3s/registries.yaml
Normal file
14
scripts/k3s/registries.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
mirrors:
|
||||
zot.quorate.internal:
|
||||
endpoint:
|
||||
- "https://zot.quorate.internal"
|
||||
registry.quorate.internal:
|
||||
endpoint:
|
||||
- "https://registry.quorate.internal"
|
||||
configs:
|
||||
zot.quorate.internal:
|
||||
tls:
|
||||
ca_file: /etc/rancher/k3s/quorate-internal-ca.crt
|
||||
registry.quorate.internal:
|
||||
tls:
|
||||
ca_file: /etc/rancher/k3s/quorate-internal-ca.crt
|
||||
16
scripts/kyverno-test.sh
Executable file
16
scripts/kyverno-test.sh
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env bash
|
||||
# Run the repository Kyverno CLI test suite.
|
||||
# Local/manual gate until Argo Workflows CI exists; same entrypoint for that runner later.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
TEST_DIR="${ROOT}/vendor/platform/kyverno/tests"
|
||||
KYVERNO_VERSION="${KYVERNO_VERSION:-v1.19.2}"
|
||||
|
||||
if ! command -v kyverno >/dev/null 2>&1; then
|
||||
echo "kyverno CLI not found; install ${KYVERNO_VERSION} from kyverno releases" >&2
|
||||
exit 127
|
||||
fi
|
||||
|
||||
echo "kyverno $(kyverno version 2>/dev/null | head -1 || true)"
|
||||
exec kyverno test "${TEST_DIR}"
|
||||
89
scripts/tofu-pg-state
Executable file
89
scripts/tofu-pg-state
Executable file
|
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
export VAULT_ADDR=https://vault.quorate.internal
|
||||
|
||||
state_host="${TF_STATE_PG_HOST:-10.234.158.153}"
|
||||
state_port="${TF_STATE_PG_PORT:-5432}"
|
||||
state_db="${TF_STATE_PG_DB:-tf_state}"
|
||||
state_vault_path="${TF_STATE_PG_VAULT_PATH:-database/static-creds/tf-state}"
|
||||
source_s3_key="${VERSITYGW_TERRAFORM_STATE_ACCESS_KEY_ID:-terraform-state}"
|
||||
source_s3_path="${VERSITYGW_TERRAFORM_STATE_VAULT_PATH:-secret/versitygw/users/terraform-state}"
|
||||
|
||||
if [[ -z "${TF_CLI_CONFIG_FILE:-}" && -f dev.tfrc ]]; then
|
||||
export TF_CLI_CONFIG_FILE=dev.tfrc
|
||||
fi
|
||||
|
||||
tofu_subcommand=""
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
-chdir=*)
|
||||
;;
|
||||
-*)
|
||||
if [[ "$arg" == "-help" || "$arg" == "--help" || "$arg" == "-version" ]]; then
|
||||
tofu_subcommand="$arg"
|
||||
break
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
tofu_subcommand="$arg"
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
needs_state_credentials=true
|
||||
needs_s3_credentials=false
|
||||
case "$tofu_subcommand" in
|
||||
"" | "-help" | "--help" | "-version" | "version" | "fmt" | "validate" | "get" | "metadata")
|
||||
needs_state_credentials=false
|
||||
;;
|
||||
"init")
|
||||
for arg in "$@"; do
|
||||
if [[ "$arg" == "-backend=false" ]]; then
|
||||
needs_state_credentials=false
|
||||
break
|
||||
fi
|
||||
if [[ "$arg" == "-migrate-state" ]]; then
|
||||
needs_s3_credentials=true
|
||||
fi
|
||||
done
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$needs_state_credentials" == "false" ]]; then
|
||||
exec tofu "$@"
|
||||
fi
|
||||
|
||||
if ! command -v vault >/dev/null 2>&1; then
|
||||
echo "vault CLI is required to read PostgreSQL Terraform state credentials" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
state_user="$(vault read -field=username "$state_vault_path")"
|
||||
state_password="$(vault read -field=password "$state_vault_path")"
|
||||
|
||||
if [[ -z "$state_user" || -z "$state_password" ]]; then
|
||||
echo "Vault credential $state_vault_path is incomplete" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export PG_CONN_STR="postgres://${state_host}:${state_port}/${state_db}?sslmode=require"
|
||||
export PGUSER="$state_user"
|
||||
export PGPASSWORD="$state_password"
|
||||
|
||||
if [[ "$needs_s3_credentials" == "true" ]]; then
|
||||
source_s3_secret="$(vault kv get -field=secretAccessKey "$source_s3_path")"
|
||||
|
||||
if [[ -z "$source_s3_secret" ]]; then
|
||||
echo "Vault credential $source_s3_path is incomplete" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export AWS_ACCESS_KEY_ID="$source_s3_key"
|
||||
export AWS_SECRET_ACCESS_KEY="$source_s3_secret"
|
||||
export AWS_REGION="${AWS_REGION:-us-east-1}"
|
||||
export AWS_EC2_METADATA_DISABLED=true
|
||||
fi
|
||||
|
||||
exec tofu "$@"
|
||||
313
scripts/trust-internal-ca.sh
Executable file
313
scripts/trust-internal-ca.sh
Executable file
|
|
@ -0,0 +1,313 @@
|
|||
#!/usr/bin/env bash
|
||||
# Fetch and system-trust the internal root CA from Vault.
|
||||
#
|
||||
# Usage: ./trust-internal-ca.sh [--expected-sha256 AA:BB:...] [--kube-context NAME]
|
||||
# [--non-interactive] [--no-browsers] [--no-java]
|
||||
set -euo pipefail
|
||||
|
||||
# ── Config ────────────────────────────────────────────────────────────────────
|
||||
CERT_URL="https://vault.quorate.internal/v1/pki/ca/pem"
|
||||
CERT_NAME="internal-root-ca"
|
||||
EXPECTED_CN="Internal Root CA"
|
||||
KUBE_CONTEXT="${KUBE_CONTEXT:-quorate}"
|
||||
|
||||
# ── Flags ─────────────────────────────────────────────────────────────────────
|
||||
EXPECTED_FP=""
|
||||
NON_INTERACTIVE=false
|
||||
SKIP_BROWSERS=false
|
||||
SKIP_JAVA=false
|
||||
FETCHED_INSECURELY=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--expected-sha256) EXPECTED_FP="$2"; shift 2 ;;
|
||||
--kube-context) KUBE_CONTEXT="$2"; shift 2 ;;
|
||||
--non-interactive) NON_INTERACTIVE=true; shift ;;
|
||||
--no-browsers) SKIP_BROWSERS=true; shift ;;
|
||||
--no-java) SKIP_JAVA=true; shift ;;
|
||||
*) echo "Unknown flag: $1" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BOLD='\033[1m'; NC='\033[0m'
|
||||
info() { echo -e "${GREEN}[+]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
|
||||
die() { echo -e "${RED}[✗]${NC} $*" >&2; exit 1; }
|
||||
hr() { echo -e "${BOLD}────────────────────────────────────────────────────────${NC}"; }
|
||||
|
||||
require() { command -v "$1" &>/dev/null || die "Required tool not found: $1 — install it and retry"; }
|
||||
confirm() {
|
||||
local prompt="$1"
|
||||
if $NON_INTERACTIVE; then
|
||||
info "(non-interactive) auto-confirming: $prompt"
|
||||
return 0
|
||||
fi
|
||||
read -r -p "$prompt [yes/N] " ans
|
||||
[[ "${ans,,}" == "yes" ]] || die "Aborted by user."
|
||||
}
|
||||
|
||||
require curl
|
||||
require openssl
|
||||
|
||||
# ── Fetch ─────────────────────────────────────────────────────────────────────
|
||||
TMPDIR_WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$TMPDIR_WORK"' EXIT
|
||||
CERT_FILE="$TMPDIR_WORK/${CERT_NAME}.crt"
|
||||
|
||||
info "Fetching CA certificate from $CERT_URL ..."
|
||||
if ! curl -fsSL --max-time 15 "$CERT_URL" -o "$CERT_FILE"; then
|
||||
[[ -n "$EXPECTED_FP" ]] \
|
||||
|| die "TLS verification failed. Retry with an out-of-band --expected-sha256 pin."
|
||||
warn "TLS verification failed; retrying with the supplied fingerprint pin."
|
||||
curl --insecure -fsSL --max-time 15 "$CERT_URL" -o "$CERT_FILE" \
|
||||
|| die "Fetch failed — is vault.quorate.internal reachable?"
|
||||
FETCHED_INSECURELY=true
|
||||
fi
|
||||
|
||||
# ── Structural validation ─────────────────────────────────────────────────────
|
||||
openssl x509 -in "$CERT_FILE" -noout 2>/dev/null \
|
||||
|| die "Fetched content is not a valid PEM certificate"
|
||||
|
||||
IS_CA=$(openssl x509 -in "$CERT_FILE" -noout -text | grep -c "CA:TRUE" || true)
|
||||
[[ "$IS_CA" -gt 0 ]] || die "Certificate does not have CA:TRUE — refusing to install a non-CA cert"
|
||||
|
||||
ACTUAL_CN=$(openssl x509 -in "$CERT_FILE" -noout -subject \
|
||||
| sed -E 's/.*[Cc][Nn]\s*=\s*([^,\/]+).*/\1/')
|
||||
if [[ "$ACTUAL_CN" != "$EXPECTED_CN" ]]; then
|
||||
warn "Subject CN mismatch — expected '${EXPECTED_CN}', got '${ACTUAL_CN}'"
|
||||
confirm "CN does not match. Continue anyway?"
|
||||
fi
|
||||
|
||||
# ── Fingerprint display & verification ───────────────────────────────────────
|
||||
SHA256=$(openssl x509 -in "$CERT_FILE" -noout -fingerprint -sha256 | cut -d= -f2)
|
||||
SHA1=$(openssl x509 -in "$CERT_FILE" -noout -fingerprint -sha1 | cut -d= -f2)
|
||||
|
||||
hr
|
||||
echo -e "${BOLD}Certificate details:${NC}"
|
||||
openssl x509 -in "$CERT_FILE" -noout -subject -issuer -dates 2>/dev/null | sed 's/^/ /'
|
||||
echo ""
|
||||
echo -e " ${BOLD}SHA-256:${NC} $SHA256"
|
||||
echo -e " ${BOLD}SHA-1: ${NC} $SHA1"
|
||||
hr
|
||||
|
||||
# Pinned fingerprint check (if --expected-sha256 was passed)
|
||||
if [[ -n "$EXPECTED_FP" ]]; then
|
||||
EXPECTED_NORM="${EXPECTED_FP^^}" # normalise to upper
|
||||
ACTUAL_NORM="${SHA256^^}"
|
||||
if [[ "$EXPECTED_NORM" == "$ACTUAL_NORM" ]]; then
|
||||
info "Fingerprint matches --expected-sha256."
|
||||
else
|
||||
die "Fingerprint MISMATCH — expected $EXPECTED_FP, got $SHA256"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── kubectl cross-verify (best-effort) ───────────────────────────────────────
|
||||
if command -v kubectl &>/dev/null; then
|
||||
info "kubectl detected — attempting cross-verify against cluster ..."
|
||||
|
||||
CLUSTER_FP=""
|
||||
VAULT_POD=$(kubectl --context "$KUBE_CONTEXT" get pod -n vault \
|
||||
-l app.kubernetes.io/name=vault -o jsonpath='{.items[0].metadata.name}' \
|
||||
2>/dev/null || true)
|
||||
if [[ -n "$VAULT_POD" ]]; then
|
||||
CLUSTER_CA_PEM=$(kubectl --context "$KUBE_CONTEXT" exec -n vault "$VAULT_POD" -- \
|
||||
vault read -address=https://vault-active-tls.vault.svc.cluster.local:443 \
|
||||
-ca-cert=/vault/userconfig/vault-server-tls/ca.crt \
|
||||
-tls-server-name=vault-active-direct.vault.svc.cluster.local \
|
||||
-field=certificate pki/cert/ca 2>/dev/null || true)
|
||||
if [[ -n "$CLUSTER_CA_PEM" ]]; then
|
||||
CLUSTER_FP=$(echo "$CLUSTER_CA_PEM" \
|
||||
| openssl x509 -noout -fingerprint -sha256 2>/dev/null | cut -d= -f2 || true)
|
||||
[[ -n "$CLUSTER_FP" ]] && info "Cross-verify source: vault pod PKI CA"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "$CLUSTER_FP" ]]; then
|
||||
if [[ "${CLUSTER_FP^^}" == "${SHA256^^}" ]]; then
|
||||
info "Cluster cross-verify PASSED — fingerprints match."
|
||||
else
|
||||
warn "Cluster cross-verify FAILED — fingerprint from cluster: $CLUSTER_FP"
|
||||
warn "Fingerprint from HTTP: $SHA256"
|
||||
confirm "Fingerprints differ. Possible MITM or stale cert. Continue anyway?"
|
||||
fi
|
||||
else
|
||||
warn "Could not retrieve CA cert from cluster for cross-verify."
|
||||
warn "Manually check with: kubectl --context $KUBE_CONTEXT exec -n vault <pod> -- vault read pki/cert/ca"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── User confirmation ─────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
if $FETCHED_INSECURELY; then
|
||||
warn "TLS verification was disabled for bootstrap; the supplied SHA-256 pin matched."
|
||||
fi
|
||||
echo ""
|
||||
confirm "Install and trust this CA certificate system-wide?"
|
||||
|
||||
# ── OS trust store install ────────────────────────────────────────────────────
|
||||
install_debian() {
|
||||
local dest="/usr/local/share/ca-certificates/${CERT_NAME}.crt"
|
||||
info "Installing to $dest (Debian/Ubuntu)"
|
||||
sudo install -m 644 "$CERT_FILE" "$dest"
|
||||
sudo update-ca-certificates
|
||||
}
|
||||
|
||||
install_rhel() {
|
||||
local dest="/etc/pki/ca-trust/source/anchors/${CERT_NAME}.crt"
|
||||
info "Installing to $dest (RHEL/Fedora)"
|
||||
sudo install -m 644 "$CERT_FILE" "$dest"
|
||||
sudo update-ca-trust extract
|
||||
}
|
||||
|
||||
install_arch() {
|
||||
local dest="/etc/ca-certificates/trust-source/anchors/${CERT_NAME}.crt"
|
||||
info "Installing to $dest (Arch Linux)"
|
||||
sudo install -m 644 "$CERT_FILE" "$dest"
|
||||
sudo trust extract-compat
|
||||
}
|
||||
|
||||
install_suse() {
|
||||
local dest="/etc/pki/trust/anchors/${CERT_NAME}.crt"
|
||||
info "Installing to $dest (openSUSE)"
|
||||
sudo install -m 644 "$CERT_FILE" "$dest"
|
||||
sudo update-ca-certificates
|
||||
}
|
||||
|
||||
install_macos() {
|
||||
info "Installing to macOS System Keychain (covers Safari and Chrome)..."
|
||||
sudo security add-trusted-cert -d -r trustRoot \
|
||||
-k /Library/Keychains/System.keychain "$CERT_FILE"
|
||||
}
|
||||
|
||||
install_linux() {
|
||||
# shellcheck source=/dev/null
|
||||
. /etc/os-release
|
||||
local id="${ID:-unknown}" like="${ID_LIKE:-}"
|
||||
if [[ "$id" == "debian" || "$id" == "ubuntu" || "$like" == *"debian"* ]]; then install_debian
|
||||
elif [[ "$id" == "fedora" || "$like" == *"fedora"* || "$like" == *"rhel"* || "$id" == "rhel" || "$id" == "centos" ]]; then install_rhel
|
||||
elif [[ "$id" == "arch" || "$like" == *"arch"* ]]; then install_arch
|
||||
elif [[ "$id" == "opensuse"* || "$like" == *"suse"* ]]; then install_suse
|
||||
else
|
||||
warn "Unknown distro '$id' — attempting Debian-style install"
|
||||
install_debian
|
||||
fi
|
||||
}
|
||||
|
||||
# ── NSS (Firefox / Chrome on Linux) ──────────────────────────────────────────
|
||||
install_nss() {
|
||||
if ! command -v certutil &>/dev/null; then
|
||||
warn "certutil not found — skipping NSS databases."
|
||||
warn " Debian/Ubuntu: sudo apt install libnss3-tools"
|
||||
warn " RHEL/Fedora: sudo dnf install nss-tools"
|
||||
return
|
||||
fi
|
||||
|
||||
local added=0
|
||||
|
||||
# Collect NSS database directories from Firefox and Chrome/Chromium
|
||||
local nss_dirs=()
|
||||
|
||||
# Firefox profiles (standard, snap, flatpak)
|
||||
while IFS= read -r -d '' db_dir; do
|
||||
nss_dirs+=("$db_dir")
|
||||
done < <(find \
|
||||
"$HOME/.mozilla/firefox" \
|
||||
"$HOME/snap/firefox/common/.mozilla/firefox" \
|
||||
"$HOME/.var/app/org.mozilla.firefox/.mozilla/firefox" \
|
||||
2>/dev/null -maxdepth 2 -name "cert9.db" -printf '%h\0' || true)
|
||||
|
||||
# Chrome/Chromium shared NSS db
|
||||
for chrome_db in \
|
||||
"$HOME/.pki/nssdb" \
|
||||
"$HOME/.config/google-chrome/Default" \
|
||||
"$HOME/.config/chromium/Default" \
|
||||
"$HOME/snap/chromium/current/.pki/nssdb"; do
|
||||
[[ -d "$chrome_db" ]] && nss_dirs+=("$chrome_db")
|
||||
done
|
||||
|
||||
if [[ ${#nss_dirs[@]} -eq 0 ]]; then
|
||||
warn "No NSS databases found under \$HOME."
|
||||
return
|
||||
fi
|
||||
|
||||
for db_dir in "${nss_dirs[@]}"; do
|
||||
info " NSS: $db_dir"
|
||||
# Remove any stale entry first (ignore failure if not present)
|
||||
certutil -D -n "$CERT_NAME" -d "sql:$db_dir" 2>/dev/null || true
|
||||
if certutil -A -n "$CERT_NAME" -t "CT,," -i "$CERT_FILE" -d "sql:$db_dir" 2>/dev/null; then
|
||||
((added++))
|
||||
else
|
||||
warn "Failed to add cert to $db_dir"
|
||||
fi
|
||||
done
|
||||
|
||||
info "Added to $added NSS database(s)."
|
||||
info "Restart Firefox/Chrome for the change to take effect."
|
||||
}
|
||||
|
||||
# ── Java truststore ───────────────────────────────────────────────────────────
|
||||
install_java() {
|
||||
local keytool
|
||||
keytool=$(command -v keytool 2>/dev/null || true)
|
||||
if [[ -z "$keytool" ]]; then
|
||||
warn "keytool not found — skipping Java truststore."
|
||||
return
|
||||
fi
|
||||
|
||||
# Find JAVA_HOME cacerts (handles OpenJDK layout and SDKMAN)
|
||||
local cacerts=""
|
||||
for candidate in \
|
||||
"${JAVA_HOME:-}/lib/security/cacerts" \
|
||||
"${JAVA_HOME:-}/jre/lib/security/cacerts" \
|
||||
"$(dirname "$(readlink -f "$(command -v java)")")/../lib/security/cacerts" \
|
||||
"$(dirname "$(readlink -f "$(command -v java)")")/../jre/lib/security/cacerts"; do
|
||||
[[ -f "$candidate" ]] && { cacerts="$candidate"; break; }
|
||||
done
|
||||
|
||||
if [[ -z "$cacerts" ]]; then
|
||||
warn "Could not locate Java cacerts file — skipping Java truststore."
|
||||
return
|
||||
fi
|
||||
|
||||
info "Adding to Java truststore: $cacerts"
|
||||
sudo keytool -importcert -noprompt \
|
||||
-alias "$CERT_NAME" \
|
||||
-file "$CERT_FILE" \
|
||||
-keystore "$cacerts" \
|
||||
-storepass changeit \
|
||||
&& info "Java truststore updated." \
|
||||
|| warn "Java truststore update failed (may already be present)."
|
||||
}
|
||||
|
||||
# ── Main ──────────────────────────────────────────────────────────────────────
|
||||
OS=$(uname -s)
|
||||
case "$OS" in
|
||||
Linux) install_linux ;;
|
||||
Darwin) install_macos ;;
|
||||
*) die "Unsupported OS: $OS" ;;
|
||||
esac
|
||||
|
||||
if [[ "$OS" == "Linux" ]] && ! $SKIP_BROWSERS; then
|
||||
echo ""
|
||||
if $NON_INTERACTIVE; then
|
||||
install_nss
|
||||
else
|
||||
read -r -p "Also install into Firefox/Chrome NSS databases for $USER? [y/N] " ans
|
||||
[[ "${ans,,}" == "y" ]] && install_nss || true
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! $SKIP_JAVA; then
|
||||
echo ""
|
||||
if $NON_INTERACTIVE; then
|
||||
install_java
|
||||
else
|
||||
read -r -p "Also install into Java truststore? [y/N] " ans
|
||||
[[ "${ans,,}" == "y" ]] && install_java || true
|
||||
fi
|
||||
fi
|
||||
|
||||
hr
|
||||
info "CA certificate installed. New processes and tools will trust it immediately."
|
||||
info "Browser sessions and Java apps need a restart to pick up the change."
|
||||
47
scripts/vlq.sh
Normal file
47
scripts/vlq.sh
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# Source this file to define vlq(), a small authenticated VictoriaLogs query
|
||||
# helper backed by the caller's current Vault session.
|
||||
vlq() (
|
||||
set -euo pipefail
|
||||
|
||||
export VAULT_ADDR="${VAULT_ADDR:-https://vault.quorate.internal}"
|
||||
|
||||
command -v vault >/dev/null 2>&1 || {
|
||||
printf 'vlq: vault CLI is required\n' >&2
|
||||
return 127
|
||||
}
|
||||
|
||||
command -v vlogscli-prod >/dev/null 2>&1 || {
|
||||
printf 'vlq: vlogscli-prod is required\n' >&2
|
||||
return 127
|
||||
}
|
||||
|
||||
local server="${VLQ_SERVER:-https://logs.quorate.internal/select/logsql/query}"
|
||||
local vault_path="${VLQ_VAULT_PATH:-secret/victorialogs/vmauth/query}"
|
||||
local vault_field="${VLQ_VAULT_FIELD:-token}"
|
||||
local history_file="${VLQ_HISTORY_FILE:-${XDG_STATE_HOME:-$HOME/.local/state}/vlq/history}"
|
||||
local tmpdir token_file
|
||||
|
||||
tmpdir="$(mktemp -d "${TMPDIR:-/tmp}/vlq.XXXXXX")"
|
||||
chmod 700 "$tmpdir"
|
||||
trap 'rm -rf "$tmpdir"' EXIT
|
||||
|
||||
token_file="$tmpdir/token"
|
||||
|
||||
vault kv get -field="$vault_field" "$vault_path" >"$token_file"
|
||||
chmod 600 "$token_file"
|
||||
|
||||
mkdir -p "$(dirname "$history_file")"
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
printf '%s\n\nq\n' "$*" | vlogscli-prod \
|
||||
-datasource.url="$server" \
|
||||
-bearerToken="file://$token_file" \
|
||||
-historyFile="$history_file"
|
||||
return
|
||||
fi
|
||||
|
||||
vlogscli-prod \
|
||||
-datasource.url="$server" \
|
||||
-bearerToken="file://$token_file" \
|
||||
-historyFile="$history_file"
|
||||
)
|
||||
42
scripts/vmq.sh
Normal file
42
scripts/vmq.sh
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Source this file to define vmq(), a small authenticated VictoriaMetrics query
|
||||
# helper backed by the caller's current Vault session.
|
||||
vmq() (
|
||||
set -euo pipefail
|
||||
|
||||
export VAULT_ADDR="${VAULT_ADDR:-https://vault.quorate.internal}"
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
printf 'usage: vmq <promql expression>\n' >&2
|
||||
return 2
|
||||
fi
|
||||
|
||||
command -v vault >/dev/null 2>&1 || {
|
||||
printf 'vmq: vault CLI is required\n' >&2
|
||||
return 127
|
||||
}
|
||||
|
||||
command -v promtool >/dev/null 2>&1 || {
|
||||
printf 'vmq: promtool is required\n' >&2
|
||||
return 127
|
||||
}
|
||||
|
||||
local server="${VMQ_SERVER:-https://metrics.quorate.internal/prometheus}"
|
||||
local vault_path="${VMQ_VAULT_PATH:-secret/victoriametrics/vmauth/query}"
|
||||
local vault_field="${VMQ_VAULT_FIELD:-token}"
|
||||
local tmpdir token_file http_config
|
||||
|
||||
tmpdir="$(mktemp -d "${TMPDIR:-/tmp}/vmq.XXXXXX")"
|
||||
chmod 700 "$tmpdir"
|
||||
trap 'rm -rf "$tmpdir"' EXIT
|
||||
|
||||
token_file="$tmpdir/token"
|
||||
http_config="$tmpdir/http-config.yml"
|
||||
|
||||
vault kv get -field="$vault_field" "$vault_path" >"$token_file"
|
||||
chmod 600 "$token_file"
|
||||
|
||||
printf 'authorization:\n type: Bearer\n credentials_file: %s\n' "$token_file" >"$http_config"
|
||||
chmod 600 "$http_config"
|
||||
|
||||
promtool query instant --http.config.file="$http_config" "$server" "$*"
|
||||
)
|
||||
Loading…
Reference in a new issue