Merge pull request #86319 from flokli/google-oslogin
nixos/google-oslogin: bump package, make tests more readable
This commit is contained in:
commit
c2c30d926c
@ -22,6 +22,8 @@ in {
|
|||||||
client = { ... }: {};
|
client = { ... }: {};
|
||||||
};
|
};
|
||||||
testScript = ''
|
testScript = ''
|
||||||
|
MOCKUSER = "mockuser_nixos_org"
|
||||||
|
MOCKADMIN = "mockadmin_nixos_org"
|
||||||
start_all()
|
start_all()
|
||||||
|
|
||||||
server.wait_for_unit("mock-google-metadata.service")
|
server.wait_for_unit("mock-google-metadata.service")
|
||||||
@ -29,10 +31,10 @@ in {
|
|||||||
|
|
||||||
# mockserver should return a non-expired ssh key for both mockuser and mockadmin
|
# mockserver should return a non-expired ssh key for both mockuser and mockadmin
|
||||||
server.succeed(
|
server.succeed(
|
||||||
'${pkgs.google-compute-engine-oslogin}/bin/google_authorized_keys mockuser | grep -q "${snakeOilPublicKey}"'
|
f'${pkgs.google-compute-engine-oslogin}/bin/google_authorized_keys {MOCKUSER} | grep -q "${snakeOilPublicKey}"'
|
||||||
)
|
)
|
||||||
server.succeed(
|
server.succeed(
|
||||||
'${pkgs.google-compute-engine-oslogin}/bin/google_authorized_keys mockadmin | grep -q "${snakeOilPublicKey}"'
|
f'${pkgs.google-compute-engine-oslogin}/bin/google_authorized_keys {MOCKADMIN} | grep -q "${snakeOilPublicKey}"'
|
||||||
)
|
)
|
||||||
|
|
||||||
# install snakeoil ssh key on the client, and provision .ssh/config file
|
# install snakeoil ssh key on the client, and provision .ssh/config file
|
||||||
@ -50,20 +52,22 @@ in {
|
|||||||
client.fail("ssh ghost@server 'true'")
|
client.fail("ssh ghost@server 'true'")
|
||||||
|
|
||||||
# we should be able to connect as mockuser
|
# we should be able to connect as mockuser
|
||||||
client.succeed("ssh mockuser@server 'true'")
|
client.succeed(f"ssh {MOCKUSER}@server 'true'")
|
||||||
# but we shouldn't be able to sudo
|
# but we shouldn't be able to sudo
|
||||||
client.fail(
|
client.fail(
|
||||||
"ssh mockuser@server '/run/wrappers/bin/sudo /run/current-system/sw/bin/id' | grep -q 'root'"
|
f"ssh {MOCKUSER}@server '/run/wrappers/bin/sudo /run/current-system/sw/bin/id' | grep -q 'root'"
|
||||||
)
|
)
|
||||||
|
|
||||||
# we should also be able to log in as mockadmin
|
# we should also be able to log in as mockadmin
|
||||||
client.succeed("ssh mockadmin@server 'true'")
|
client.succeed(f"ssh {MOCKADMIN}@server 'true'")
|
||||||
# pam_oslogin_admin.so should now have generated a sudoers file
|
# pam_oslogin_admin.so should now have generated a sudoers file
|
||||||
server.succeed("find /run/google-sudoers.d | grep -q '/run/google-sudoers.d/mockadmin'")
|
server.succeed(
|
||||||
|
f"find /run/google-sudoers.d | grep -q '/run/google-sudoers.d/{MOCKADMIN}'"
|
||||||
|
)
|
||||||
|
|
||||||
# and we should be able to sudo
|
# and we should be able to sudo
|
||||||
client.succeed(
|
client.succeed(
|
||||||
"ssh mockadmin@server '/run/wrappers/bin/sudo /run/current-system/sw/bin/id' | grep -q 'root'"
|
f"ssh {MOCKADMIN}@server '/run/wrappers/bin/sudo /run/current-system/sw/bin/id' | grep -q 'root'"
|
||||||
)
|
)
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
|
@ -7,24 +7,29 @@ import hashlib
|
|||||||
import base64
|
import base64
|
||||||
|
|
||||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||||
|
from urllib.parse import urlparse, parse_qs
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
SNAKEOIL_PUBLIC_KEY = os.environ['SNAKEOIL_PUBLIC_KEY']
|
SNAKEOIL_PUBLIC_KEY = os.environ['SNAKEOIL_PUBLIC_KEY']
|
||||||
|
MOCKUSER="mockuser_nixos_org"
|
||||||
|
MOCKADMIN="mockadmin_nixos_org"
|
||||||
|
|
||||||
|
|
||||||
def w(msg):
|
def w(msg: bytes):
|
||||||
sys.stderr.write(f"{msg}\n")
|
sys.stderr.write(f"{msg}\n")
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
|
|
||||||
|
|
||||||
def gen_fingerprint(pubkey):
|
def gen_fingerprint(pubkey: str):
|
||||||
decoded_key = base64.b64decode(pubkey.encode("ascii").split()[1])
|
decoded_key = base64.b64decode(pubkey.encode("ascii").split()[1])
|
||||||
return hashlib.sha256(decoded_key).hexdigest()
|
return hashlib.sha256(decoded_key).hexdigest()
|
||||||
|
|
||||||
def gen_email(username):
|
|
||||||
|
def gen_email(username: str):
|
||||||
"""username seems to be a 21 characters long number string, so mimic that in a reproducible way"""
|
"""username seems to be a 21 characters long number string, so mimic that in a reproducible way"""
|
||||||
return str(int(hashlib.sha256(username.encode()).hexdigest(), 16))[0:21]
|
return str(int(hashlib.sha256(username.encode()).hexdigest(), 16))[0:21]
|
||||||
|
|
||||||
|
|
||||||
def gen_mockuser(username: str, uid: str, gid: str, home_directory: str, snakeoil_pubkey: str) -> Dict:
|
def gen_mockuser(username: str, uid: str, gid: str, home_directory: str, snakeoil_pubkey: str) -> Dict:
|
||||||
snakeoil_pubkey_fingerprint = gen_fingerprint(snakeoil_pubkey)
|
snakeoil_pubkey_fingerprint = gen_fingerprint(snakeoil_pubkey)
|
||||||
# seems to be a 21 characters long numberstring, so mimic that in a reproducible way
|
# seems to be a 21 characters long numberstring, so mimic that in a reproducible way
|
||||||
@ -56,7 +61,8 @@ def gen_mockuser(username: str, uid: str, gid: str, home_directory: str, snakeoi
|
|||||||
|
|
||||||
|
|
||||||
class ReqHandler(BaseHTTPRequestHandler):
|
class ReqHandler(BaseHTTPRequestHandler):
|
||||||
def _send_json_ok(self, data):
|
|
||||||
|
def _send_json_ok(self, data: dict):
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
self.send_header('Content-type', 'application/json')
|
self.send_header('Content-type', 'application/json')
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
@ -64,29 +70,62 @@ class ReqHandler(BaseHTTPRequestHandler):
|
|||||||
w(out)
|
w(out)
|
||||||
self.wfile.write(out)
|
self.wfile.write(out)
|
||||||
|
|
||||||
|
def _send_json_success(self, success=True):
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-type', 'application/json')
|
||||||
|
self.end_headers()
|
||||||
|
out = json.dumps({"success": success}).encode()
|
||||||
|
w(out)
|
||||||
|
self.wfile.write(out)
|
||||||
|
|
||||||
|
def _send_404(self):
|
||||||
|
self.send_response(404)
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
def do_GET(self):
|
def do_GET(self):
|
||||||
p = str(self.path)
|
p = str(self.path)
|
||||||
# mockuser and mockadmin are allowed to login, both use the same snakeoil public key
|
pu = urlparse(p)
|
||||||
if p == '/computeMetadata/v1/oslogin/users?username=mockuser' \
|
params = parse_qs(pu.query)
|
||||||
or p == '/computeMetadata/v1/oslogin/users?uid=1009719690':
|
|
||||||
self._send_json_ok(gen_mockuser(username='mockuser', uid='1009719690', gid='1009719690',
|
|
||||||
home_directory='/home/mockuser', snakeoil_pubkey=SNAKEOIL_PUBLIC_KEY))
|
|
||||||
elif p == '/computeMetadata/v1/oslogin/users?username=mockadmin' \
|
|
||||||
or p == '/computeMetadata/v1/oslogin/users?uid=1009719691':
|
|
||||||
self._send_json_ok(gen_mockuser(username='mockadmin', uid='1009719691', gid='1009719691',
|
|
||||||
home_directory='/home/mockadmin', snakeoil_pubkey=SNAKEOIL_PUBLIC_KEY))
|
|
||||||
|
|
||||||
# mockuser is allowed to login
|
# users endpoint
|
||||||
elif p == f"/computeMetadata/v1/oslogin/authorize?email={gen_email('mockuser')}&policy=login":
|
if pu.path == "/computeMetadata/v1/oslogin/users":
|
||||||
self._send_json_ok({'success': True})
|
# mockuser and mockadmin are allowed to login, both use the same snakeoil public key
|
||||||
|
if params.get('username') == [MOCKUSER] or params.get('uid') == ["1009719690"]:
|
||||||
|
username = MOCKUSER
|
||||||
|
uid = "1009719690"
|
||||||
|
elif params.get('username') == [MOCKADMIN] or params.get('uid') == ["1009719691"]:
|
||||||
|
username = MOCKADMIN
|
||||||
|
uid = "1009719691"
|
||||||
|
else:
|
||||||
|
self._send_404()
|
||||||
|
return
|
||||||
|
|
||||||
# mockadmin may also become root
|
self._send_json_ok(gen_mockuser(username=username, uid=uid, gid=uid, home_directory=f"/home/{username}", snakeoil_pubkey=SNAKEOIL_PUBLIC_KEY))
|
||||||
elif p == f"/computeMetadata/v1/oslogin/authorize?email={gen_email('mockadmin')}&policy=login" or p == f"/computeMetadata/v1/oslogin/authorize?email={gen_email('mockadmin')}&policy=adminLogin":
|
return
|
||||||
self._send_json_ok({'success': True})
|
|
||||||
|
# authorize endpoint
|
||||||
|
elif pu.path == "/computeMetadata/v1/oslogin/authorize":
|
||||||
|
# is user allowed to login?
|
||||||
|
if params.get("policy") == ["login"]:
|
||||||
|
# mockuser and mockadmin are allowed to login
|
||||||
|
if params.get('email') == [gen_email(MOCKUSER)] or params.get('email') == [gen_email(MOCKADMIN)]:
|
||||||
|
self._send_json_success()
|
||||||
|
return
|
||||||
|
self._send_json_success(False)
|
||||||
|
return
|
||||||
|
# is user allowed to become root?
|
||||||
|
elif params.get("policy") == ["adminLogin"]:
|
||||||
|
# only mockadmin is allowed to become admin
|
||||||
|
self._send_json_success((params['email'] == [gen_email(MOCKADMIN)]))
|
||||||
|
return
|
||||||
|
# send 404 for other policies
|
||||||
|
else:
|
||||||
|
self._send_404()
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
sys.stderr.write(f"Unhandled path: {p}\n")
|
sys.stderr.write(f"Unhandled path: {p}\n")
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
self.send_response(501)
|
self.send_response(404)
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(b'')
|
self.wfile.write(b'')
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{ stdenv
|
{ stdenv
|
||||||
|
, lib
|
||||||
, fetchFromGitHub
|
, fetchFromGitHub
|
||||||
, curl
|
, curl
|
||||||
, json_c
|
, json_c
|
||||||
@ -8,22 +9,20 @@
|
|||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "google-compute-engine-oslogin";
|
pname = "google-compute-engine-oslogin";
|
||||||
version = "1.5.3";
|
version = "20200325.00";
|
||||||
# from packages/google-compute-engine-oslogin/packaging/debian/changelog
|
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "GoogleCloudPlatform";
|
owner = "GoogleCloudPlatform";
|
||||||
repo = "compute-image-packages";
|
repo = "guest-oslogin";
|
||||||
rev = "20190522";
|
rev = version;
|
||||||
sha256 = "16jbbrnz49g843h813r408dbvfa2hicf8canxwbfxr2kzhv7ycmm";
|
sha256 = "03hk95pgzcgy6ginp8zdy0fbk88m6n65qq22jq490z1xwbjffm8r";
|
||||||
};
|
};
|
||||||
sourceRoot = "source/packages/google-compute-engine-oslogin";
|
|
||||||
|
|
||||||
postPatch = ''
|
postPatch = ''
|
||||||
# change sudoers dir from /var/google-sudoers.d to /run/google-sudoers.d (managed through systemd-tmpfiles)
|
# change sudoers dir from /var/google-sudoers.d to /run/google-sudoers.d (managed through systemd-tmpfiles)
|
||||||
substituteInPlace pam_module/pam_oslogin_admin.cc --replace /var/google-sudoers.d /run/google-sudoers.d
|
substituteInPlace src/pam/pam_oslogin_admin.cc --replace /var/google-sudoers.d /run/google-sudoers.d
|
||||||
# fix "User foo not allowed because shell /bin/bash does not exist"
|
# fix "User foo not allowed because shell /bin/bash does not exist"
|
||||||
substituteInPlace compat.h --replace /bin/bash ${bashInteractive}/bin/bash
|
substituteInPlace src/include/compat.h --replace /bin/bash ${bashInteractive}/bin/bash
|
||||||
'';
|
'';
|
||||||
|
|
||||||
buildInputs = [ curl.dev pam ];
|
buildInputs = [ curl.dev pam ];
|
||||||
@ -31,15 +30,15 @@ stdenv.mkDerivation rec {
|
|||||||
NIX_CFLAGS_COMPILE="-I${json_c.dev}/include/json-c";
|
NIX_CFLAGS_COMPILE="-I${json_c.dev}/include/json-c";
|
||||||
NIX_CFLAGS_LINK="-L${json_c}/lib";
|
NIX_CFLAGS_LINK="-L${json_c}/lib";
|
||||||
|
|
||||||
installPhase = ''
|
makeFlags = [
|
||||||
mkdir -p $out/{bin,lib}
|
"VERSION=${version}"
|
||||||
|
"DESTDIR=${placeholder "out"}"
|
||||||
install -Dm755 libnss_cache_google-compute-engine-oslogin-${version}.so $out/lib/libnss_cache_oslogin.so.2
|
"PREFIX=/"
|
||||||
install -Dm755 libnss_google-compute-engine-oslogin-${version}.so $out/lib/libnss_oslogin.so.2
|
"BINDIR=/bin"
|
||||||
|
"LIBDIR=/lib"
|
||||||
install -Dm755 pam_oslogin_admin.so pam_oslogin_login.so $out/lib
|
"PAMDIR=/lib"
|
||||||
install -Dm755 google_{oslogin_nss_cache,authorized_keys} $out/bin
|
"MANDIR=/share/man"
|
||||||
'';
|
];
|
||||||
|
|
||||||
enableParallelBuilding = true;
|
enableParallelBuilding = true;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user