Skip to content
Open
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
2 changes: 1 addition & 1 deletion cli/cenclave/src/cenclave/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import os

__version__ = "1.0.0a6"
__version__ = "1.0.0a11"

# PCCS to retrieve collaterals
PCCS_URL = os.getenv("PCCS_URL", default="https://pccs.cosmian.com")
Expand Down
18 changes: 18 additions & 0 deletions cli/cenclave/src/cenclave/command/sgx_operator/spawn.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,20 @@ def add_subparser(subparsers):
help="enclave size to spawn (must be a power of 2)",
)

parser.add_argument(
"--client-certificate",
type=Path,
help="bundle for client certificate authentication",
)

parser.add_argument(
"--ssl-verify-mode",
type=int,
help="Either CERT_OPTIONAL (1) or CERT_REQUIRED (2). Default to CERT_REQUIRED.",
choices=[1, 2],
default=2,
)

parser.add_argument(
"--signer-key",
type=Path,
Expand Down Expand Up @@ -157,6 +171,10 @@ def run(args) -> None:
subject_alternative_name=args.san,
app_id=uuid4(),
expiration_date=int((datetime.today() + timedelta(days=args.days)).timestamp()),
client_certificate=(
args.client_certificate.read_text() if args.client_certificate else None
),
ssl_verify_mode=(args.ssl_verify_mode if args.client_certificate else None),
app_dir=workspace,
application=code_config.python_application,
healthcheck=code_config.healthcheck_endpoint,
Expand Down
13 changes: 9 additions & 4 deletions cli/cenclave/src/cenclave/core/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from uuid import UUID

import requests
import urllib3
from pydantic import BaseModel

from cenclave.core.base64 import base64url_encode
Expand Down Expand Up @@ -122,11 +123,15 @@ def is_ready(

if response.status_code != 503 and "Mse-Status" not in response.headers:
return True
except requests.exceptions.Timeout:
return False
except requests.exceptions.SSLError:
except (
requests.exceptions.Timeout,
requests.exceptions.SSLError,
):
return False
except requests.exceptions.ConnectionError:
except requests.exceptions.ConnectionError as exc:
err, *_ = exc.args
if isinstance(err, urllib3.exceptions.ProtocolError):
return True
return False

return False
34 changes: 25 additions & 9 deletions cli/cenclave/src/cenclave/core/no_sgx_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class NoSgxDockerConfig(BaseModel):
subject: str
subject_alternative_name: str
expiration_date: Optional[int]
client_certificate: Optional[str]
ssl_verify_mode: Optional[int]
size: int
app_id: UUID
application: str
Expand All @@ -24,25 +26,37 @@ class NoSgxDockerConfig(BaseModel):

def cmd(self) -> List[str]:
"""Serialize the docker command args."""
command = [
args = [
"--application",
self.application,
"--size",
f"{self.size}M",
"--subject",
self.subject,
"--san",
self.subject_alternative_name,
"--id",
str(self.app_id),
"--application",
self.application,
"--dry-run",
"--subject",
self.subject,
]

if self.expiration_date:
command.append("--expiration")
command.append(str(self.expiration_date))
args.append("--expiration")
args.append(str(self.expiration_date))

if client_certificate := self.client_certificate:
if ssl_verify_mode := self.ssl_verify_mode:
args.extend(
[
"--client-certificate",
client_certificate,
"--ssl-verify-mode",
str(ssl_verify_mode),
]
)

args.append("--dry-run")

return command
return args

def volumes(self, app_path: Path) -> Dict[str, Dict[str, str]]:
"""Define the docker volumes."""
Expand All @@ -60,6 +74,8 @@ def from_sgx(docker_config: SgxDockerConfig):
subject=docker_config.subject,
subject_alternative_name=docker_config.subject_alternative_name,
expiration_date=docker_config.expiration_date,
client_certificate=docker_config.client_certificate,
ssl_verify_mode=docker_config.ssl_verify_mode,
size=docker_config.size,
app_id=docker_config.app_id,
application=docker_config.application,
Expand Down
45 changes: 38 additions & 7 deletions cli/cenclave/src/cenclave/core/sgx_docker.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""cenclave.core.sgx_docker module."""

from pathlib import Path
from typing import Any, ClassVar, Dict, List, Tuple
from typing import Any, ClassVar, Dict, List, Optional, Tuple
from uuid import UUID

from pydantic import BaseModel
from pydantic import BaseModel, validator


class SgxDockerConfig(BaseModel):
Expand All @@ -17,6 +17,8 @@ class SgxDockerConfig(BaseModel):
subject: str
subject_alternative_name: str
expiration_date: int
client_certificate: Optional[str]
ssl_verify_mode: Optional[int]
app_dir: Path
application: str
healthcheck: str
Expand All @@ -27,23 +29,50 @@ class SgxDockerConfig(BaseModel):
docker_label: ClassVar[str] = "cenclave"
entrypoint: ClassVar[str] = "cenclave-run"

# pylint: disable=no-self-argument
@validator("ssl_verify_mode")
def check_ssl_verify_mode(cls, v, values):
"""Validate ssl_verify_mode with client_certificate."""
if "ssl_verify_mode" in values and not values["client_certificate"]:
raise ValueError("no client_certificate with ssl_verify_mode")

if v and v not in (1, 2):
raise ValueError(
"ssl_verify_mode must be 1 (CERT_OPTIONAL) or 2 (CERT_REQUIRED)"
)

return v

def cmd(self) -> List[str]:
"""Serialize the docker command args."""
return [
args = [
"--application",
self.application,
"--size",
f"{self.size}M",
"--subject",
self.subject,
"--san",
self.subject_alternative_name,
"--id",
str(self.app_id),
"--application",
self.application,
"--subject",
self.subject,
"--expiration",
str(self.expiration_date),
]

if client_certificate := self.client_certificate:
if ssl_verify_mode := self.ssl_verify_mode:
args.extend(
[
"--client-certificate",
client_certificate,
"--ssl-verify-mode",
str(ssl_verify_mode),
]
)

return args

def ports(self) -> Dict[str, Tuple[str, str]]:
"""Define the docker ports."""
return {"443/tcp": (self.host, str(self.port))}
Expand Down Expand Up @@ -123,6 +152,8 @@ def load(docker_attrs: Dict[str, Any], docker_labels: Any):
subject_alternative_name=data_map["san"],
app_id=UUID(data_map["id"]),
expiration_date=int(data_map["expiration"]),
client_certificate=data_map.get("client-certificate"),
ssl_verify_mode=data_map.get("ssl-verify-mode"),
app_dir=Path(app["Source"]),
application=data_map["application"],
port=int(port["443/tcp"][0]["HostPort"]),
Expand Down
2 changes: 2 additions & 0 deletions cli/cenclave/src/cenclave/model/evidence.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ def save(self, path: Path) -> None:
if self.input_args.expiration_date
else None
),
"client_certificate": self.input_args.client_certificate,
"ssl_verify_mode": self.input_args.ssl_verify_mode,
"size": self.input_args.size,
"app_id": str(self.input_args.app_id),
"application": self.input_args.application,
Expand Down
2 changes: 2 additions & 0 deletions cli/cenclave/tests/data/evidence.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"subject": "CN=localhost,O=MyApp Company,C=FR,L=Paris,ST=Ile-de-France",
"subject_alternative_name": "localhost",
"expiration_date": 1714058115,
"client_certificate": null,
"ssl_verify_mode": null,
"size": 4096,
"app_id": "63322f85-1ff8-4483-91ae-f18d7398d157",
"application": "app:app"
Expand Down
28 changes: 19 additions & 9 deletions cli/cenclave/tests/test_no_sgx_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ def test_from_sgx():
subject="CN=localhost,O=Big Company,C=FR,L=Paris,ST=Ile-de-France",
subject_alternative_name="localhost",
expiration_date=1714058115,
client_certificate=None,
ssl_verify_mode=None,
size=4096,
app_id="63322f85-1ff8-4483-91ae-f18d7398d157",
application="app:app",
Expand All @@ -26,6 +28,8 @@ def test_from_sgx():
subject_alternative_name="localhost",
app_id="63322f85-1ff8-4483-91ae-f18d7398d157",
expiration_date=1714058115,
client_certificate=None,
ssl_verify_mode=None,
app_dir="/home/cosmian/workspace/sgx_operator/",
application="app:app",
healthcheck="/health",
Expand All @@ -42,6 +46,8 @@ def test_volumes():
subject="CN=localhost,O=Big Company,C=FR,L=Paris,ST=Ile-de-France",
subject_alternative_name="localhost",
expiration_date=1714058115,
client_certificate=None,
ssl_verify_mode=None,
size=4096,
app_id="63322f85-1ff8-4483-91ae-f18d7398d157",
application="app:app",
Expand All @@ -61,45 +67,49 @@ def test_cmd():
subject="CN=localhost,O=Big Company,C=FR,L=Paris,ST=Ile-de-France",
subject_alternative_name="localhost",
expiration_date=1714058115,
client_certificate=None,
ssl_verify_mode=None,
size=4096,
app_id="63322f85-1ff8-4483-91ae-f18d7398d157",
application="app:app",
)

assert ref_conf.cmd() == [
"--application",
"app:app",
"--size",
"4096M",
"--subject",
"CN=localhost,O=Big Company,C=FR,L=Paris,ST=Ile-de-France",
"--san",
"localhost",
"--id",
"63322f85-1ff8-4483-91ae-f18d7398d157",
"--application",
"app:app",
"--dry-run",
"--subject",
"CN=localhost,O=Big Company,C=FR,L=Paris,ST=Ile-de-France",
"--expiration",
"1714058115",
"--dry-run",
]

ref_conf = NoSgxDockerConfig(
subject="CN=localhost,O=Big Company,C=FR,L=Paris,ST=Ile-de-France",
subject_alternative_name="localhost",
client_certificate=None,
ssl_verify_mode=None,
size=4096,
app_id="63322f85-1ff8-4483-91ae-f18d7398d157",
application="app:app",
)

assert ref_conf.cmd() == [
"--application",
"app:app",
"--size",
"4096M",
"--subject",
"CN=localhost,O=Big Company,C=FR,L=Paris,ST=Ile-de-France",
"--san",
"localhost",
"--id",
"63322f85-1ff8-4483-91ae-f18d7398d157",
"--application",
"app:app",
"--subject",
"CN=localhost,O=Big Company,C=FR,L=Paris,ST=Ile-de-France",
"--dry-run",
]
Loading