Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion cbscore/src/cbscore/builder/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class Builder:
ccache_path: Path | None
skip_build: bool
force: bool
tls_verify: bool

def __init__(
self,
Expand All @@ -72,6 +73,7 @@ def __init__(
*,
skip_build: bool = False,
force: bool = False,
tls_verify: bool = True
) -> None:
self.desc = desc
self.config = config
Expand All @@ -82,6 +84,7 @@ def __init__(
self.ccache_path = config.paths.ccache
self.skip_build = skip_build
self.force = force
self.tls_verify = tls_verify

try:
vault_config = self.config.get_vault_config()
Expand Down Expand Up @@ -109,7 +112,7 @@ async def run(self) -> None:
raise BuilderError(msg=msg) from e

container_img_uri = get_container_canonical_uri(self.desc)
if skopeo_image_exists(container_img_uri, self.secrets):
if skopeo_image_exists(container_img_uri, self.secrets, tls_verify=self.tls_verify):
logger.info(f"image '{container_img_uri}' already exists -- do not build!")
return
else:
Expand Down
9 changes: 6 additions & 3 deletions cbscore/src/cbscore/builder/prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,19 @@ async def _cb(s: str) -> None:
raise BuilderError(msg="unable to install dependencies")

# install cosign rpm
rc, _, stderr = await async_run_cmd(
rc, stdout, stderr = await async_run_cmd(
[
"rpm",
"-Uvh",
"https://github.com/sigstore/cosign/releases/download/v2.4.3/"
+ "cosign-2.4.3-1.x86_64.rpm",
],
outcb=_cb,
)
if rc != 0:
logger.debug(stdout)
if rc == 2 and re.match(".*already installed.*", stderr):
msg = f'skip install cosign. allready installed'
logger.debug(msg)
elif rc != 0:
msg = f"error installing cosign package: {stderr}"
logger.error(msg)
raise BuilderError(msg)
Expand Down
15 changes: 15 additions & 0 deletions cbscore/src/cbscore/cmds/builds.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@
is_flag=True,
default=False,
)
@click.option(
"--tls-verify",
help="Require HTTPS and verify certificates when talking to the container registry or daemon.",
default=True,
)
@pass_ctx
def cmd_build(
ctx: Ctx,
Expand All @@ -136,6 +141,7 @@ def cmd_build(
log_file_path: Path | None,
skip_build: bool,
force: bool,
tls_verify: bool,
) -> None:
assert ctx.config_path

Expand Down Expand Up @@ -192,6 +198,7 @@ def cmd_build(
log_file_path=log_file_path,
skip_build=skip_build,
force=force,
tls_verify=tls_verify,
)
)

Expand Down Expand Up @@ -245,12 +252,18 @@ def cmd_runner_grp() -> None:
is_flag=True,
default=False,
)
@click.option(
"--tls-verify",
help="Require HTTPS and verify certificates when talking to the container registry or daemon.",
default=True,
)
@with_config
def cmd_runner_build(
config: Config,
desc_path: Path,
skip_build: bool,
force: bool,
tls_verify: bool,
) -> None:
upload_to_str = (
config.storage.s3.url
Expand Down Expand Up @@ -285,6 +298,7 @@ def cmd_runner_build(
registry: {registry_str}
skip build: {skip_build}
force: {force}
tls-verify: {tls_verify}
""")

if not desc_path.exists():
Expand All @@ -303,6 +317,7 @@ def cmd_runner_build(
config,
skip_build=skip_build,
force=force,
tls_verify=tls_verify,
)
except BuilderError as e:
logger.error(f"unable to initialize builder: {e}")
Expand Down
49 changes: 34 additions & 15 deletions cbscore/src/cbscore/images/signing.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,34 +36,53 @@ def __str__(self) -> str:
return f"Signing Error: {self.msg}"


def sign(
registry: str, img: str, secrets: SecretsMgr, transit: str
) -> tuple[int, str, str]:
def _get_signing_params(
registry: str, secrets: SecretsMgr, transit: str
) -> tuple[str, str, str, str]:
"""
Check preconditions and return (username, password, transit_mount, transit_key).

Raises SigningError if any prerequisite is missing.
"""
if not secrets.has_vault():
msg = "no vault configured, can't sign image"
logger.error(msg)
raise SigningError(msg)
raise SigningError("no vault configured, can't sign image")

assert secrets.vault is not None

if not secrets.has_transit_key(transit):
msg = f"vault transit key '{transit}' not found, can't sign image"
logger.error(msg)
raise SigningError(msg)
raise SigningError(f"vault transit key '{transit}' not found, can't sign image")

try:
_, username, password = secrets.registry_creds(registry)
except SecretsMgrError as e:
msg = f"unable to obtain registry credentials for '{registry}': {e}"
logger.error(msg)
raise SigningError(msg) from e
raise SigningError(
f"unable to obtain registry credentials for '{registry}': {e}"
) from e

try:
transit_mount, transit_key = secrets.transit(transit)
except SecretsMgrError as e:
msg = f"unable to obtain transit key '{transit}': {e}"
logger.error(msg)
raise SigningError(msg) from e
raise SigningError(f"unable to obtain transit key '{transit}': {e}") from e

return username, password, transit_mount, transit_key


def can_sign(registry: str, secrets: SecretsMgr, transit: str) -> bool:
try:
_get_signing_params(registry, secrets, transit)
except SigningError as e:
logger.debug(e.msg)
return False
else:
return True


def sign(
registry: str, img: str, secrets: SecretsMgr, transit: str
) -> tuple[int, str, str]:
username, password, transit_mount, transit_key = _get_signing_params(
registry, secrets, transit
)

cmd: CmdArgs = [
"cosign",
Expand Down
37 changes: 22 additions & 15 deletions cbscore/src/cbscore/images/skopeo.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from cbscore.images import get_image_name
from cbscore.images import logger as parent_logger
from cbscore.images.errors import ImageNotFoundError, SkopeoError
from cbscore.images.signing import sign
from cbscore.images.signing import can_sign, sign
from cbscore.utils import CmdArgs, Password, run_cmd
from cbscore.utils.containers import get_container_image_base_uri
from cbscore.utils.secrets import SecretsMgrError
Expand Down Expand Up @@ -99,20 +99,23 @@ def skopeo_copy(

logger.info(f"copied '{src}' to '{dst}'")

try:
retcode, out, err = sign(dst_registry, dst, secrets, transit)
except SkopeoError as e:
logger.exception(f"error signing image '{dst}'")
raise e # noqa: TRY201
if can_sign(dst_registry, secrets, transit):
try:
retcode, out, err = sign(dst_registry, dst, secrets, transit)
except SkopeoError as e:
logger.exception(f"error signing image '{dst}'")
raise e # noqa: TRY201

if retcode != 0:
logger.error(f"error signing image '{dst}': {err}")
raise SkopeoError()
if retcode != 0:
logger.error(f"error signing image '{dst}': {err}")
raise SkopeoError()

logger.info(f"signed image '{dst}': {out}")
logger.info(f"signed image '{dst}': {out}")
else:
logger.warning(f"signing skipped for image '{dst}'")


def skopeo_inspect(img: str, secrets: SecretsMgr) -> str:
def skopeo_inspect(img: str, secrets: SecretsMgr, *, tls_verify: bool = True) -> str:
logger.debug(f"inspect image '{img}'")

try:
Expand All @@ -132,6 +135,7 @@ def skopeo_inspect(img: str, secrets: SecretsMgr) -> str:
retcode, raw_out, err = skopeo(
[
"inspect",
f"--tls-verify={tls_verify}",
"--creds",
Password(f"{user}:{passwd}"),
f"docker://{img}",
Expand All @@ -143,19 +147,22 @@ def skopeo_inspect(img: str, secrets: SecretsMgr) -> str:

if retcode != 0:
msg = f"error inspecting image '{img}': {err}"
logger.error(msg)
if re.match(r".*not\s+found.*", err):
if retcode == 2 or re.match(r".*not\s+found.*", err):
logger.debug(msg)
raise ImageNotFoundError(img) from None
logger.error(msg)
raise SkopeoError(msg) from None

return raw_out


def skopeo_image_exists(img: str, secrets: SecretsMgr) -> bool:
def skopeo_image_exists(
img: str, secrets: SecretsMgr, *, tls_verify: bool = True
) -> bool:
logger.debug(f"check if image '{img}' exists")

try:
_ = skopeo_inspect(img, secrets)
_ = skopeo_inspect(img, secrets, tls_verify=tls_verify)
except ImageNotFoundError:
logger.debug(f"image '{img}' does not exist")
return False
Expand Down
4 changes: 3 additions & 1 deletion cbscore/src/cbscore/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ async def runner(
log_out_cb: AsyncRunCmdOutCallback | None = None,
skip_build: bool = False,
force: bool = False,
tls_verify: bool = True,
) -> None:
our_actual_loc = Path(__file__).parent

Expand Down Expand Up @@ -174,6 +175,7 @@ async def runner(
log to file: {log_file_path if log_file_path else "not logging to file"}
skip build: {skip_build}
force: {force}
tls-verify: {tls_verify}
""")

if not entrypoint_path.exists() or not entrypoint_path.is_file():
Expand Down Expand Up @@ -250,7 +252,7 @@ async def runner(
logger.error(msg)
raise RunnerError(msg) from e

podman_args = ["--desc", desc_mount_loc]
podman_args = ["--desc", desc_mount_loc, f"--tls-verify={tls_verify}"]
podman_volumes = {
desc_file_path.resolve().as_posix(): desc_mount_loc,
cbscore_path.resolve().as_posix(): "/runner/cbscore",
Expand Down