Skip to content

Commit 9894102

Browse files
author
Malte Münch
authored
Merge pull request #66 from gardenlinux/remove-signing
Remove signing
2 parents 1bdfe24 + c430019 commit 9894102

File tree

6 files changed

+249
-502
lines changed

6 files changed

+249
-502
lines changed

poetry.lock

Lines changed: 239 additions & 313 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "python_gardenlinux_lib"
3-
version = "0.3.0"
3+
version = "0.4.0"
44
description = "Contains tools to work with the features directory of gardenlinux, for example deducting dependencies from feature sets or validating cnames"
55
authors = ["Garden Linux Maintainers <[email protected]>"]
66
license = "Apache-2.0"
@@ -19,7 +19,6 @@ jsonschema = "^4.23.0"
1919
oras = { git = "https://github.com/oras-project/oras-py.git", rev="caf8db5b279382335fbb1f6d7402ed9b73618d37" }
2020
python-dotenv = "^1.0.1"
2121
cryptography = "^43.0.0"
22-
boto3 = "1.35.30"
2322

2423

2524
[tool.poetry.group.dev.dependencies]

src/python_gardenlinux_lib/oras/crypto.py

Lines changed: 0 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,4 @@
11
import hashlib
2-
import logging
3-
import os
4-
5-
import boto3
6-
from babel.messages import Message
7-
from cryptography.hazmat.primitives import hashes
8-
from cryptography.hazmat.primitives.asymmetric import padding
9-
from cryptography.hazmat.primitives.serialization import load_pem_private_key
10-
from cryptography.hazmat.backends import default_backend
11-
from cryptography.exceptions import InvalidSignature
12-
from cryptography import x509
13-
import base64
14-
15-
16-
class Signer:
17-
"""
18-
Signer
19-
20-
abstract class defining the methods for signing and verifying data
21-
"""
22-
23-
def sign_data(self, data_str: str) -> str:
24-
pass
25-
26-
def verify_signature(self, data_str: str, signature: str):
27-
pass
28-
29-
30-
class KMSSigner(Signer):
31-
"""
32-
KMSSigner
33-
34-
implementation of Signer interface using AWS KMS
35-
"""
36-
37-
def __init__(self, arn: str):
38-
self.kms_client = boto3.client("kms")
39-
# check if client works
40-
key_info = self.kms_client.describe_key(KeyId=arn)
41-
42-
if "SIGN" not in key_info["KeyMetadata"]["KeyUsage"]:
43-
raise Exception("Key is missing the sign property")
44-
if "VERIFY" not in key_info["KeyMetadata"]["KeyUsage"]:
45-
raise Exception("Key is missing the verify property")
46-
if "RSASSA_PSS_SHA_256" not in key_info["KeyMetadata"]["SigningAlgorithms"]:
47-
raise Exception(
48-
"Key is missing the required signing algorithm (RSASSA_PSS_SHA_256)"
49-
)
50-
# seems to be fine, use it
51-
self.arn = arn
52-
53-
def sign_data(self, data_str: str) -> str:
54-
signature = self.kms_client.sign(
55-
KeyId=self.arn,
56-
MessageType="RAW",
57-
SigningAlgorithm="RSASSA_PSS_SHA_256",
58-
Message=data_str.encode("utf-8"),
59-
)["Signature"]
60-
return base64.b64encode(signature).decode("utf-8")
61-
62-
def verify_signature(self, data_str: str, signature: str):
63-
if not self.kms_client.verify(
64-
KeyId=self.arn,
65-
Message=data_str.encode("utf-8"),
66-
MessageType="RAW",
67-
Signature=base64.b64decode(signature),
68-
SigningAlgorithm="RSASSA_PSS_SHA_256",
69-
)["SignatureValid"]:
70-
raise ValueError(f"Invalid Signature {signature} for data: {data_str}")
71-
72-
73-
class LocalSigner(Signer):
74-
"""
75-
LocalSigner
76-
77-
implementation of Signer interface using local certificates
78-
79-
:param private_key_file_path
80-
:param public_key_file_path
81-
"""
82-
83-
def __init__(self, private_key_file_path: str, public_key_file_path: str):
84-
with open(private_key_file_path, "rb") as key_file:
85-
self.private_key = load_pem_private_key(
86-
key_file.read(), password=None, backend=default_backend()
87-
)
88-
with open(public_key_file_path, "rb") as cert_file:
89-
cert = x509.load_pem_x509_certificate(cert_file.read(), default_backend())
90-
self.public_key = cert.public_key()
91-
92-
def sign_data(self, data_str: str) -> str:
93-
signature = self.private_key.sign(
94-
data_str.encode("utf-8"),
95-
padding.PSS(
96-
mgf=padding.MGF1(
97-
hashes.SHA256()
98-
), # Mask generation function based on SHA-256
99-
salt_length=padding.PSS.MAX_LENGTH, # Maximum salt length
100-
),
101-
hashes.SHA256(),
102-
)
103-
return base64.b64encode(signature).decode("utf-8")
104-
105-
def verify_signature(self, data_str: str, signature: str):
106-
try:
107-
self.public_key.verify(
108-
base64.b64decode(signature),
109-
data_str.encode("utf-8"),
110-
padding.PSS(
111-
mgf=padding.MGF1(
112-
hashes.SHA256()
113-
), # Mask generation function based on SHA-256
114-
salt_length=padding.PSS.MAX_LENGTH, # Maximum salt length
115-
),
116-
hashes.SHA256(),
117-
)
118-
except InvalidSignature:
119-
raise ValueError(f"Invalid Signature {signature} for data: {data_str}")
1202

1213

1224
def verify_sha256(checksum: str, data: bytes):

src/python_gardenlinux_lib/oras/registry.py

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
from python_gardenlinux_lib.oras.crypto import (
3232
calculate_sha256,
3333
verify_sha256,
34-
Signer,
3534
)
3635
from python_gardenlinux_lib.oras.defaults import (
3736
annotation_signature_key,
@@ -136,7 +135,6 @@ class GlociRegistry(Registry):
136135
def __init__(
137136
self,
138137
container_name: str,
139-
signer: Signer,
140138
insecure: bool = False,
141139
token: Optional[str] = None,
142140
config_path: Optional[str] = None,
@@ -146,7 +144,6 @@ def __init__(
146144
self.container_name = container_name
147145
self.registry_url = self.container.registry
148146
self.config_path = config_path
149-
self.signer = signer
150147
if not token:
151148
logger.info("No Token provided.")
152149
else:
@@ -168,7 +165,6 @@ def get_manifest_json(
168165
get_manifest = f"{self.prefix}://{container.manifest_url()}"
169166
response = self.do_request(get_manifest, "GET", headers=headers)
170167
self._check_200_response(response)
171-
self.verify_manifest_signature(response.json())
172168
return response
173169

174170
@ensure_container
@@ -252,7 +248,6 @@ def get_manifest_meta_data_by_cname(
252248
and manifest_meta["annotations"]["architecture"] == arch
253249
and manifest_meta["platform"]["os.version"] == version
254250
):
255-
self.verify_manifest_meta_signature(manifest_meta)
256251
return manifest_meta
257252

258253
return None
@@ -278,7 +273,6 @@ def get_manifest_by_digest(
278273
self._check_200_response(response)
279274
manifest = response.json()
280275
verify_sha256(digest, response.content)
281-
self.verify_manifest_signature(manifest)
282276
jsonschema.validate(manifest, schema=oras_manifest_schema)
283277
return manifest
284278

@@ -367,8 +361,6 @@ def attach_layer(
367361
self.container, cname, version, architecture
368362
)
369363

370-
self.verify_manifest_signature(manifest)
371-
372364
layer = self.create_layer(file_path, cname, version, architecture, media_type)
373365
self._check_200_response(self.upload_blob(file_path, self.container, layer))
374366

@@ -384,7 +376,6 @@ def attach_layer(
384376
new_manifest_metadata["size"] = self.get_manifest_size(manifest_container)
385377
new_manifest_metadata["platform"] = NewPlatform(architecture, version)
386378

387-
self.sign_manifest_entry(new_manifest_metadata, version, architecture, cname)
388379
new_index = self.update_index(old_manifest_digest, new_manifest_metadata)
389380
self._check_200_response(self.upload_index(new_index))
390381

@@ -535,6 +526,7 @@ def push_image_manifest(
535526
:param str build_artifacts_dir: directory where the build artifacts are located
536527
:param str feature_set: the expanded list of the included features of this manifest. It will be set in the
537528
manifest itself and in the index entry for this manifest
529+
:returns the digest of the pushed manifest
538530
"""
539531

540532
# TODO: construct oci_artifacts default data
@@ -594,6 +586,8 @@ def push_image_manifest(
594586
f"{self.container_name}-{cname}-{architecture}"
595587
)
596588

589+
local_digest = f"sha256:{hashlib.sha256(json.dumps(manifest_image).encode('utf-8')).hexdigest()}"
590+
597591
self._check_200_response(
598592
self.upload_manifest(manifest_image, manifest_container)
599593
)
@@ -603,13 +597,14 @@ def push_image_manifest(
603597
attach_state(metadata_annotations, "")
604598
metadata_annotations["feature_set"] = feature_set
605599
manifest_digest = self.get_digest(manifest_container)
600+
if manifest_digest != local_digest:
601+
raise ValueError("local and remotely calculated digests do not match")
606602
manifest_index_metadata = NewManifestMetadata(
607603
manifest_digest,
608604
self.get_manifest_size(manifest_container),
609605
metadata_annotations,
610606
NewPlatform(architecture, version),
611607
)
612-
self.sign_manifest_entry(manifest_index_metadata, version, architecture, cname)
613608

614609
old_manifest_meta_data = self.get_manifest_meta_data_by_cname(
615610
self.container, cname, version, architecture
@@ -624,7 +619,7 @@ def push_image_manifest(
624619
self._check_200_response(self.upload_index(new_index))
625620

626621
print(f"Successfully pushed {self.container}")
627-
return response
622+
return local_digest
628623

629624
def create_layer(
630625
self,
@@ -639,9 +634,6 @@ def create_layer(
639634
layer["annotations"] = {
640635
oras.defaults.annotation_title: os.path.basename(file_path),
641636
}
642-
self.sign_layer(
643-
layer, cname, version, architecture, checksum_sha256, media_type
644-
)
645637
return layer
646638

647639
def push_from_tar(self, architecture: str, version: str, cname: str, tar: str):
@@ -667,7 +659,7 @@ def push_from_tar(self, architecture: str, version: str, cname: str, tar: str):
667659
break
668660
file.close()
669661

670-
self.push_image_manifest(
662+
digest = self.push_image_manifest(
671663
architecture, cname, version, tmpdir, oci_metadata, features
672664
)
673665
except Exception as e:
@@ -677,6 +669,7 @@ def push_from_tar(self, architecture: str, version: str, cname: str, tar: str):
677669
exit(1)
678670
shutil.rmtree(tmpdir, ignore_errors=True)
679671
print("removed tmp files.")
672+
return digest
680673

681674

682675
def extract_tar(tar: str, tmpdir: str):

tests/test_push_image.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import pytest
44
import os
55

6-
from python_gardenlinux_lib.oras.crypto import LocalSigner
76
from python_gardenlinux_lib.oras.registry import GlociRegistry
87
from python_gardenlinux_lib.features import parse_features
98

@@ -34,13 +33,7 @@ def test_push_example(version, cname, arch):
3433
cname, version, arch, GARDENLINUX_ROOT_DIR_EXAMPLE
3534
)
3635
container_name = f"{CONTAINER_NAME_ZOT_EXAMPLE}:{version}"
37-
signer = LocalSigner(
38-
private_key_file_path="cert/oci-sign.key",
39-
public_key_file_path="cert/oci-sign.crt",
40-
)
41-
a_registry = GlociRegistry(
42-
container_name=container_name, insecure=True, signer=signer
43-
)
36+
a_registry = GlociRegistry(container_name=container_name, insecure=True)
4437
features = parse_features.get_features(cname, GARDENLINUX_ROOT_DIR_EXAMPLE)
4538
a_registry.push_image_manifest(
4639
arch,

tests/test_push_image_kms.py

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)