authentik ldap working; home-assistant auth with LDAP working

This commit is contained in:
Ellis Rahhal 2024-04-25 23:49:16 -07:00
parent 1a2597de28
commit 29877e469d
6 changed files with 317 additions and 206 deletions

View file

@ -1,6 +1,14 @@
TODOS TODOS
===== =====
* HA Authentication
* Use local network authentication, then use Authentik proxy auth in front
* LDAP auth is annoying, and presents a different auth page
* Look into auto-initialization for HA: https://github.com/home-assistant/core/issues/16554
* Using auth_manager API to create user, or edit .storage/auth directly / deploy it
* Authentik
* Auto LDAP deploy
* https://docs.goauthentik.io/docs/providers/ldap/generic_setup
* setup VLANs * setup VLANs
* https://wiki.nftables.org/wiki-nftables/index.php/Main_Page * https://wiki.nftables.org/wiki-nftables/index.php/Main_Page
* https://serverfault.com/questions/858556/transparent-firewall-with-nftables-and-vlans * https://serverfault.com/questions/858556/transparent-firewall-with-nftables-and-vlans

View file

@ -1,5 +1,9 @@
{ config, ... }: { pkgs, ... }:
{ {
environment.systemPackages = with pkgs; [
openldap
];
services.authentik = { services.authentik = {
enable = true; enable = true;
# Deployed SOPS file # Deployed SOPS file
@ -18,8 +22,16 @@
}; };
}; };
# HTTP port services.authentik-ldap = {
networking.firewall.allowedTCPPorts = [ 9000 ]; enable = true;
# Deployed SOPS file
environmentFile = "/run/secrets/authentik/authentik-ldap-env";
};
networking.firewall.allowedTCPPorts = [
# 3389 # LDAP
9000 # Web GUI
];
sops.secrets = { sops.secrets = {
"authentik/authentik-env" = { "authentik/authentik-env" = {
@ -31,6 +43,15 @@
path = "/run/secrets/authentik/authentik-env"; path = "/run/secrets/authentik/authentik-env";
restartUnits = [ "authentik.service" ]; restartUnits = [ "authentik.service" ];
}; };
"authentik/authentik-ldap-env" = {
format = "yaml";
# @TODO: Move secrets to this folder
sopsFile = ../secrets/authentik.yaml;
owner = "homefree";
path = "/run/secrets/authentik/authentik-ldap-env";
restartUnits = [ "authentik-ldap.service" ];
};
"authentik/postgres-password" = { "authentik/postgres-password" = {
format = "yaml"; format = "yaml";
# @TODO: Move secrets to this folder # @TODO: Move secrets to this folder

View file

@ -12,6 +12,11 @@ in
#----------------------------------------------------------------------------------------------------- #-----------------------------------------------------------------------------------------------------
imports = [ imports = [
# On first run, this has to be commented out, and a single user created.
# Afterward, it can be re-included
## @TODO: Auto-initializatin for HA
## See: https://github.com/home-assistant/core/issues/16554
./ldap.nix
./weather.nix ./weather.nix
]; ];
@ -47,7 +52,7 @@ in
"script ui" = "!include scripts.yaml"; "script ui" = "!include scripts.yaml";
"group manual" = groups; "group manual" = groups;
"group ui" = "!include groups.yaml"; # "group ui" = "!include groups.yaml";
http = { http = {
use_x_forwarded_for = true; use_x_forwarded_for = true;
@ -112,18 +117,18 @@ in
} }
]; ];
media_player = [ # media_player = [
{ # {
platform = "yamaha"; # platform = "yamaha";
host = "10.0.0.41"; # host = "10.0.0.41";
source_names = { # source_names = {
HDMI1 = "PC HDMI"; # HDMI1 = "PC HDMI";
}; # };
zone_names = { # zone_names = {
Main_Zone = "Family Room"; # Main_Zone = "Family Room";
}; # };
} # }
]; # ];
sensor = [ sensor = [
# See: https://github.com/home-assistant/core/issues/64839 # See: https://github.com/home-assistant/core/issues/64839
@ -151,193 +156,193 @@ in
}; };
}; };
} }
{ # {
platform = "hp_ilo"; # platform = "hp_ilo";
host = "10.0.0.9"; # host = "10.0.0.9";
username = "Administrator"; # username = "Administrator";
# @TODO: REMOVE # # @TODO: REMOVE
password = "CHANGEME"; # password = "CHANGEME";
monitored_variables = [ # monitored_variables = [
{ # {
name = "CPU fanspeed"; # name = "CPU fanspeed";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "%"; # unit_of_measurement = "%";
value_template = "{{ ilo_data.fans[\"Fan 1\"].speed[0] }}"; # value_template = "{{ ilo_data.fans[\"Fan 1\"].speed[0] }}";
} # }
{ # {
name = "Fan 2"; # name = "Fan 2";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "%"; # unit_of_measurement = "%";
value_template = "{{ ilo_data.fans[\"Fan 2\"].speed[0] }}"; # value_template = "{{ ilo_data.fans[\"Fan 2\"].speed[0] }}";
} # }
{ # {
name = "Fan 3"; # name = "Fan 3";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "%"; # unit_of_measurement = "%";
value_template = "{{ ilo_data.fans[\"Fan 3\"].speed[0] }}"; # value_template = "{{ ilo_data.fans[\"Fan 3\"].speed[0] }}";
} # }
{ # {
name = "Server Health"; # name = "Server Health";
sensor_type = "server_health"; # sensor_type = "server_health";
value_template = "{{ ilo_data.health_at_a_glance }}"; # value_template = "{{ ilo_data.health_at_a_glance }}";
} # }
{ # {
name = "Server Power Readings (raw)"; # name = "Server Power Readings (raw)";
sensor_type = "server_power_readings"; # sensor_type = "server_power_readings";
} # }
{ # {
name = "Server Power Status (raw)"; # name = "Server Power Status (raw)";
sensor_type = "server_power_status"; # sensor_type = "server_power_status";
} # }
{ # {
name = "Server health (raw)"; # name = "Server health (raw)";
sensor_type = "server_health"; # sensor_type = "server_health";
} # }
{ # {
name = "Inlet temperature"; # name = "Inlet temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\"01-Inlet Ambient\"].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"01-Inlet Ambient\"].currentreading[0] }}";
} # }
{ # {
name = "Inlet temperature (raw)"; # name = "Inlet temperature (raw)";
sensor_type = "server_health"; # sensor_type = "server_health";
value_template = "{{ ilo_data.temperature[\"01-Inlet Ambient\"] }}"; # value_template = "{{ ilo_data.temperature[\"01-Inlet Ambient\"] }}";
} # }
{ # {
name = "CPU 1 temperature"; # name = "CPU 1 temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\"02-CPU 1\"].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"02-CPU 1\"].currentreading[0] }}";
} # }
{ # {
name = "P1 DIMM 1-4 temperature"; # name = "P1 DIMM 1-4 temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\"03-P1 DIMM 1-4\"].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"03-P1 DIMM 1-4\"].currentreading[0] }}";
} # }
{ # {
name = "HD Max temperature"; # name = "HD Max temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\"04-HD Max\"].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"04-HD Max\"].currentreading[0] }}";
} # }
{ # {
name = "Chipset temperature"; # name = "Chipset temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\"05-Chipset\"].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"05-Chipset\"].currentreading[0] }}";
} # }
{ # {
name = "VR P1 temperature"; # name = "VR P1 temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\"07-VR P1\"].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"07-VR P1\"].currentreading[0] }}";
} # }
{ # {
name = "SuperCAP Max temperature"; # name = "SuperCAP Max temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\"08-Supercap Max\"].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"08-Supercap Max\"].currentreading[0] }}";
} # }
{ # {
name = "iLO Zone temperature"; # name = "iLO Zone temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\"09-iLO Zone\"].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"09-iLO Zone\"].currentreading[0] }}";
} # }
{ # {
name = "LOM Zon temperature"; # name = "LOM Zon temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\"11-LOM Zone\"].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"11-LOM Zone\"].currentreading[0] }}";
} # }
{ # {
name = "PCI 2 temperature"; # name = "PCI 2 temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\"13-PCI 2\"].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"13-PCI 2\"].currentreading[0] }}";
} # }
{ # {
name = "PCI 1 Zone temperature"; # name = "PCI 1 Zone temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\"14-PCI 1 Zone\"].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"14-PCI 1 Zone\"].currentreading[0] }}";
} # }
{ # {
name = "PCI 2 Zone temperature"; # name = "PCI 2 Zone temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\15-PCI 2 Zone\].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"15-PCI 2 Zone\"].currentreading[0] }}";
} # }
{ # {
name = "System Board temperature"; # name = "System Board temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\"16-System Board\"].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"16-System Board\"].currentreading[0] }}";
} # }
{ # {
name = "Sys Exhaust temperature"; # name = "Sys Exhaust temperature";
sensor_type = "server_health"; # sensor_type = "server_health";
unit_of_measurement = "°C"; # unit_of_measurement = "°C";
value_template = "{{ ilo_data.temperature[\"17-Sys Exhaust\"].currentreading[0] }}"; # value_template = "{{ ilo_data.temperature[\"17-Sys Exhaust\"].currentreading[0] }}";
} # }
]; # ];
} # }
{ # {
# This includes the config necessary for a washer and dryer. # # This includes the config necessary for a washer and dryer.
# Code for dishwasher and mini-washer may be commented out as-needed, # # Code for dishwasher and mini-washer may be commented out as-needed,
# and are presented only for reference purposes. # # and are presented only for reference purposes.
#
# NOTE: YOUR ENTITY NAMES MAY BE DIFFERENT, THEN THIS WON'T WORK WITHOUT TWEAKING # # NOTE: YOUR ENTITY NAMES MAY BE DIFFERENT, THEN THIS WON'T WORK WITHOUT TWEAKING
# ================================================================================= # # =================================================================================
# If your washer doesn't have entities named sensor.washer, sensor.washer_run_state # # If your washer doesn't have entities named sensor.washer, sensor.washer_run_state
# (and similar for dryer), you have to change the names throughout here! # # (and similar for dryer), you have to change the names throughout here!
#
# NOTE: THIS CODE EXPECTS YOUR THINQ INTEGRATION TO RETURN ENGLISH STRINGS # # NOTE: THIS CODE EXPECTS YOUR THINQ INTEGRATION TO RETURN ENGLISH STRINGS
# ================================================================================= # # =================================================================================
# if your LG account is in another region/language, this will probably break unless # # if your LG account is in another region/language, this will probably break unless
# you take the time to change out state strings like "Standby". Do this by watching # # you take the time to change out state strings like "Standby". Do this by watching
# your machine's entities change states during a run, or look at its history. # # your machine's entities change states during a run, or look at its history.
#
platform = "template"; # platform = "template";
sensors = { # sensors = {
front_load_washer_door_lock = { # front_load_washer_door_lock = {
friendly_name = "Washer Door Lock"; # friendly_name = "Washer Door Lock";
value_template = "{{ state_attr('sensor.front_load_washer','door_lock') }}"; # value_template = "{{ state_attr('sensor.front_load_washer','door_lock') }}";
}; # };
front_load_washer_time_display = { # front_load_washer_time_display = {
friendly_name = "Washer Time Display"; # friendly_name = "Washer Time Display";
value_template = '' # value_template = ''
{% if is_state('sensor.front_load_washer_run_state', '-') %} # {% if is_state('sensor.front_load_washer_run_state', '-') %}
{% elif is_state('sensor.front_load_washer_run_state', 'unavailable') %} # {% elif is_state('sensor.front_load_washer_run_state', 'unavailable') %}
{% elif is_state('sensor.front_load_washer_run_state', 'Standby') %} # {% elif is_state('sensor.front_load_washer_run_state', 'Standby') %}
-:-- # -:--
{% else %} # {% else %}
{{ state_attr("sensor.front_load_washer","remain_time").split(":")[:-1] | join(':') }} # {{ state_attr("sensor.front_load_washer","remain_time").split(":")[:-1] | join(':') }}
{% endif %} # {% endif %}
''; # '';
}; # };
#
dryer_time_display = { # dryer_time_display = {
friendly_name = "Dryer Time Display"; # friendly_name = "Dryer Time Display";
value_template = '' # value_template = ''
{% if is_state('sensor.dryer_run_state', '-') %} # {% if is_state('sensor.dryer_run_state', '-') %}
{% elif is_state('sensor.dryer_run_state', 'unavailable') %} # {% elif is_state('sensor.dryer_run_state', 'unavailable') %}
{% elif is_state('sensor.dryer_run_state', 'Standby') %} # {% elif is_state('sensor.dryer_run_state', 'Standby') %}
-:-- # -:--
{% else %} # {% else %}
{{ state_attr("sensor.dryer","remain_time").split(":")[:-1] | join(':') }} # {{ state_attr("sensor.dryer","remain_time").split(":")[:-1] | join(':') }}
{% endif %} # {% endif %}
''; # '';
}; # };
#
blank = { # blank = {
friendly_name = "Blank Sensor"; # friendly_name = "Blank Sensor";
value_template = ""; # value_template = "";
}; # };
}; # };
} # }
]; ];
}; };
}; };

View file

@ -0,0 +1,63 @@
{
stdenv,
fetchFromGitHub,
makeWrapper,
openldap,
coreutils,
gnused,
gnugrep,
lib,
}:
stdenv.mkDerivation {
name = "ldap-auth-sh";
src = fetchFromGitHub {
owner = "efficiosoft";
repo = "ldap-auth-sh";
rev = "93b2c00413942908139e37c7432a12bcb705ac87";
sha256 = "1pymp6ki353aqkigr89g7hg5x1mny68m31c3inxf1zr26n5s2kz8";
};
nativeBuildInputs = [ makeWrapper ];
installPhase = ''
mkdir -p $out/etc
cat > $out/etc/home-assistant.cfg << 'EOF'
CLIENT="ldapsearch"
SERVER="ldap://localhost:3389"
USERDN="cn=$(ldap_dn_escape "$username"),ou=users,dc=ldap,dc=goauthentik,dc=io"
PW=$password
BASEDN="dc=ldap,dc=goauthentik,dc=io"
SCOPE="subtree"
FILTER="(&(objectClass=user)(sAMAccountName=$(ldap_dn_escape "$username")))"
# USERNAME_PATTERN='^[a-z|A-Z|0-9|_|-|.|@]+$'
on_auth_success() {
# print the meta entries for use in HA
if echo "$output" | grep -qE '^(dn|DN):: '; then
# ldapsearch base64 encodes non-ascii
output=$(echo "$output" | sed -n -e "s/^\(dn\|DN\)\s*::\s*\(.*\)$/\2/p" | base64 -d)
else
output=$(echo "$output" | sed -n -e "s/^\(dn\|DN\)\s*:\s*\(.*\)$/\2/p")
fi
name=$(echo "$output" | sed -nr 's/^cn=([^,]+).*/\1/Ip')
[ -z "$name" ] || echo "name=$name"
}
on_auth_failure() {
echo "$output"
}
EOF
install -D -m755 ldap-auth.sh $out/bin/ldap-auth.sh
wrapProgram $out/bin/ldap-auth.sh \
--prefix PATH : ${
lib.makeBinPath [
openldap
coreutils
gnused
gnugrep
]
} \
--add-flags "$out/etc/home-assistant.cfg"
'';
}

View file

@ -0,0 +1,13 @@
{ pkgs, ... }:
let
ldap-auth-sh = pkgs.callPackage ./ldap-auth-sh.nix;
in
{
services.home-assistant.config.homeassistant.auth_providers = [
{
type = "command_line";
command = "${ldap-auth-sh}/bin/ldap-auth.sh";
meta = true;
}
];
}

View file

@ -1,14 +1,15 @@
authentik: authentik:
postgres-password: ENC[AES256_GCM,data:HezgfCXKIiZcvJmoda4=,iv:umWPgOPwcQtnCFKHRKgyjKhhOLZgYfA4VEjyv/mxv2Q=,tag:mkAquT40K4bta9wq1lfUig==,type:str] postgres-password: ENC[AES256_GCM,data:HezgfCXKIiZcvJmoda4=,iv:umWPgOPwcQtnCFKHRKgyjKhhOLZgYfA4VEjyv/mxv2Q=,tag:mkAquT40K4bta9wq1lfUig==,type:str]
authentik-env: ENC[AES256_GCM,data:GC0euKHPIU4cALcr6ZVOY3UqrTz8BdW7fwN0XJXlMYBtRVSpoNd+b8JLx5ZEzvVSNm3JQGwz9PusJPcqLGY01Zx2pIEj+/Gc4rLiUIdAGvTVROGYcpDLkC9TG5iNLGZFbG7bcvOEjcJ8BhJ8MTqhmQOI+l0kvFymq7gAByqqvIxAWFeIQI1ye7metJhTBsKQoYrZHDGgTeNnVkl6S1Ab6JQTuU4DoGDHNpPzKJs4djOvrlv6VKYt9hUkad+JrB7RrLOpV8zY+1Jui/6lBpS9mCaX3PuhK1NQ1QVM5OEM6WrUHW4NvPR2cc0M6PUwq1bIyen6B0+sqXwh3wcmgvlxWlAuBPXDNl04ucm1i+YtT1GRDQMj3RJfAEi9Onxl2tYro1VmkAul+i6mjiehn4csT4bP0tck9HaQC0HemZDW4NirJsyNJjG8DOXO+mCD/zOKav6AIgCvg3wO6POl2S3bP/hFK0xugO+AOo7T9OdF8n2uBCFWuvVqdI0TmqlU5I2n1XR+tTzS4kdX6v9aDuItZf/M/L2u,iv:r/i9Dx+kUOTQ6PIkWBW0ug15R+/SNhrMIJPL0uYWvuo=,tag:g8AJjZ/5T3voBZcszwXLtA==,type:str] authentik-env: ENC[AES256_GCM,data:h4c0qEj0dK71GeBEoHhG2G9w+3hnEvayhqcpyjXrxa8uaTLtw2+4YgU1DpQIR+PtzyMAXqonuP5xK5x02F49a3Jo3W6RGT2sdNkGpNYIPD9T1EMHnj9Gj8CF3OhsPBt7eRzBYTLbQfwD7EvtCDd+kHPA8TXDdxqAeFJrES58EgEKoO24v6I7zJzWjN6QWYvRrMNvllPq6ELno1AntZxu0ugm5K/w9ZJfPLXDizJscZ3RLkPO7q9s22dtKASCiEauVTijxaTYHowZ9OvaK/jT+XljpOZUHuH/6GgL7c2dW/V1+ayFW812a55ZNdd9rZrTGRrlp1No36879rwTAunk75/24R/WfAI2mpp5nDURO1Zl4TujqxlKqTLkblaHdczDm8+zTu1K5T4syu0fwZUEQjwl9iOdHelSlNs/I3tkuJFCSJbibkGS2buZm3G2jrjJSLu8Z1M3XNvtu27lzOTnTe19mjVWA/kuIzOMF66PZU8OFhBc26JBtndKe/gBvbYIClrzoMhKdHzAFVrkQcI/BC9ErJCR,iv:ci0ZrQO9MGpqmxlgoFXiZpLrYUGdO203IFx2+7RSF+o=,tag:VM1QwU8li4umFwbfgmZdMw==,type:str]
authentik-ldap-env: ENC[AES256_GCM,data:pdzkicTb2UZBSkQLozijI1IRLWYQfJMrlzYa6JDFRTx/PKFWlxYTnyt3GKmyxD9BifDWE/26Wj0qV7MO2xhrRfrPACRoPPK03hdRiQW2BJvFCd8TylqYzxrEfzXQbD7/zm3sJ3pPEF/EDTvxZ+wcGXXXyTAyth3PvU42baArZCTaSnPPHys3FE8=,iv:+1AHRapUW1K162hP5UVeMq0oZyhUXwpRlYVZ+eUTrzY=,tag:ap56x+6mMgtSeUhMdEr+QA==,type:str]
sops: sops:
kms: [] kms: []
gcp_kms: [] gcp_kms: []
azure_kv: [] azure_kv: []
hc_vault: [] hc_vault: []
age: [] age: []
lastmodified: "2024-04-25T05:21:19Z" lastmodified: "2024-04-26T03:11:57Z"
mac: ENC[AES256_GCM,data:SKgu8RkrEZjBlgQDl7XPtG41m33cNZaKBEswMNNIi78UHZwbUbo1Biblt6kvknObaFcDJn4j9zWtPnSDhPYUbIafNNQCHQY6w/fKX1hfBoJwGT66iLRBeOHYJcJVvIYfKeoVE0x8NnNoW4MqafPbgQF8v0PxNSDzCt/w9BL5OIw=,iv:0OPFQMAwxLTiDJ+nUe1rAvVjs2nB4P50IF65kULd/nM=,tag:I8wZa4k49Qti+5f6CB3DSg==,type:str] mac: ENC[AES256_GCM,data:tjxkEzNJBThDbizdbg8kQ/fVUU7i3gpc89C2QmqXHky9mzvzY2Ve9wL0FPJXMfvLNo5ZqOG5g03Eal8vYn+cDQwSJacdCSMS3ehoC/MjntWqU7+3zHJxyynHfTpLGLgyAPjK6XAv29WXSAiyUBUov3OHpaTGo+x9ZYul6V4BHYI=,iv:vsEG1OQ6CJqv/8+ITr4xtI+zn8aoDOa+q8FSWgpR5fo=,tag:VNRDqVOLILu5mYy4fRo2Fw==,type:str]
pgp: pgp:
- created_at: "2024-04-24T05:40:34Z" - created_at: "2024-04-24T05:40:34Z"
enc: |- enc: |-