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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,9 @@ kubectl coco init --enable-sidecar
# Basic usage
kubectl coco apply -f app.yaml --sidecar

# Enable port forwarding from primary container
kubectl coco apply -f app.yaml --sidecar --sidecar-port-forward 8888

# Custom SANs for LoadBalancer or Ingress
kubectl coco apply -f app.yaml --sidecar \
--sidecar-san-ips=203.0.113.10 \
Expand Down
3 changes: 2 additions & 1 deletion TRANSFORMATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,10 @@ registry_config_uri = "kbs:///default/registry-configuration/test"

Default policy disables:
- `ExecProcessRequest`: No exec into pods
- `ReadStreamRequest`: No log streaming
- `SetPolicyRequest`: Policy changes blocked

Logs are enabled by default (`ReadStreamRequest := true`).

Custom policy can be specified in config.

#### Encoding
Expand Down
12 changes: 12 additions & 0 deletions cmd/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ var (
sidecarSANIPs string
sidecarSANDNS string
sidecarSkipAutoSANs bool
sidecarPortForward int
)

func init() {
Expand All @@ -76,6 +77,7 @@ func init() {
applyCmd.Flags().StringVar(&sidecarSANIPs, "sidecar-san-ips", "", "Comma-separated list of IP addresses for sidecar server certificate SANs")
applyCmd.Flags().StringVar(&sidecarSANDNS, "sidecar-san-dns", "", "Comma-separated list of DNS names for sidecar server certificate SANs")
applyCmd.Flags().BoolVar(&sidecarSkipAutoSANs, "sidecar-skip-auto-sans", false, "Skip auto-detection of SANs (node IPs and service DNS)")
applyCmd.Flags().IntVar(&sidecarPortForward, "sidecar-port-forward", 0, "Port to forward from primary container (requires --sidecar)")

if err := applyCmd.MarkFlagRequired("filename"); err != nil {
panic(fmt.Sprintf("failed to mark filename flag as required: %v", err))
Expand Down Expand Up @@ -122,6 +124,11 @@ func runApply(_ *cobra.Command, _ []string) error {
return fmt.Errorf("--init-container-img and --init-container-cmd require --init-container flag")
}

// Validate sidecar flags
if sidecarPortForward > 0 && !enableSidecar && !cfg.Sidecar.Enabled {
return fmt.Errorf("--sidecar-port-forward requires --sidecar flag or sidecar enabled in config")
}

// Transform manifest
if err := transformManifest(m, cfg, rc, skipApply); err != nil {
return fmt.Errorf("failed to transform manifest: %w", err)
Expand Down Expand Up @@ -244,6 +251,11 @@ func transformManifest(m *manifest.Manifest, cfg *config.CocoConfig, rc string,
cfg.Sidecar.Image = sidecarImage
}

// CLI flag can override port forward
if sidecarPortForward > 0 {
cfg.Sidecar.ForwardPort = sidecarPortForward
}

// Extract app name and namespace for per-app certificate URIs
appName := m.GetName()
if appName == "" {
Expand Down
45 changes: 45 additions & 0 deletions examples/strict-policy.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Example policy to run a specific curl command via exec to verify the CoCo environment

package agent_policy

import future.keywords.in
import future.keywords.if
import future.keywords.every

default AddARPNeighborsRequest := true
default AddSwapRequest := true
default CloseStdinRequest := true
default CopyFileRequest := true
default CreateSandboxRequest := true
default DestroySandboxRequest := true
default GetMetricsRequest := true
default GetOOMEventRequest := true
default GuestDetailsRequest := true
default ListInterfacesRequest := true
default ListRoutesRequest := true
default MemHotplugByProbeRequest := true
default OnlineCPUMemRequest := true
default PauseContainerRequest := true
default PullImageRequest := true
default RemoveContainerRequest := true
default RemoveStaleVirtiofsShareMountsRequest := true
default ReseedRandomDevRequest := true
default ResumeContainerRequest := true
default SetGuestDateTimeRequest := true
default SignalProcessRequest := true
default StartContainerRequest := true
default StartTracingRequest := true
default StatsContainerRequest := true
default StopTracingRequest := true
default TtyWinResizeRequest := true
default UpdateContainerRequest := true
default UpdateEphemeralMountsRequest := true
default UpdateInterfaceRequest := true
default UpdateRoutesRequest := true
default WaitProcessRequest := true
default WriteStreamRequest := true
default CreateContainerRequest := true
default SetPolicyRequest := false
default ExecProcessRequest := false
default ReadStreamRequest := false

6 changes: 3 additions & 3 deletions integration_test/initdata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,12 +236,12 @@ func TestInitData_Generate_DefaultPolicy(t *testing.T) {
dataSection := data["data"].(map[string]interface{})
policy := dataSection["policy.rego"].(string)

// Default policy has exec disabled
// Default policy has exec disabled but logs enabled
if !strings.Contains(policy, "ExecProcessRequest := false") {
t.Error("Default policy not found (expected ExecProcessRequest := false)")
}
if !strings.Contains(policy, "ReadStreamRequest := false") {
t.Error("Default policy should have ReadStreamRequest := false")
if !strings.Contains(policy, "ReadStreamRequest := true") {
t.Error("Default policy should have ReadStreamRequest := true")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apiVersion: v1
kind: Pod
metadata:
annotations:
io.katacontainers.config.hypervisor.cc_init_data: H4sIAAAAAAAA/4yUT2+bQBDF73wKxMU3klZqD5FySBM3jVTXCJz6EFnWsDzDiv1DdwfX7qeviNU2abTgI7M/vd15Mw9StXWSGx1fx4lv6P2Hj0m0h/PSmqF0mb5LL5MoeqqIaRMlRClbrZL4Op7NZtET2xZmK6zZydpv/vtO29Jvot6pgW6YO391cdGWPsWBdKeQCqtn0aCTiKp5LdyWYhMZ0hgKQmzbUszOk+qskuKYOtT2j1pHoqUaMdUwvD0BUVRhR73i+KaqbvLsG2TdlNb5HD96eI6vrmN2PV5ixU/qQse3ynoUXEkTJGx3/CwVgucOxLi1hkkauHGsIFOV9hCC7uDZ2eMENT9AZM4K+Jdd70j5f8w9eAF2UgSNuQcvl4v5HoaDyFC9A5NUQZmv0vODYbgdCYxSue05TCygv1juVF9/OmbOlkG/l0ZJg9vscQEdYjLq/fRIsl6pB0118KocVBXsQDrocw5t99NXnbCCSeG7dCztzhcNOSxsbzjoSQ4PVDmZyuo77EewXk+/oQCfBkqMldTBrgtw9py1YNOFrA2ptyv4WobJ8fSjBmrlSEhTjzDsz1Cy3YTQio/rIehe/gp2/9hV58T5hM27BhqO1PgcT/DflIxj4zFZk+QJ49dOMt6s7TMy/FV/BwAA//8NnmZ7PAYAAA==
io.katacontainers.config.hypervisor.cc_init_data: H4sIAAAAAAAA/4yUTW/TTBSF9/4VljfZuX1fCRaVuihNKJUIseyULKoouh6f2CPPh5m5Dgm/HpkIaIGxs/SdR+d+HpOqrZPc6Pg2TnxD/795m0QHOC+tGULX6X/pdRJFzxUxbaOEKGWrVRLfxrPZLHpm28LshDV7WfvtH99pW/pt1Ds10A1z52+urtrSpziS7hRSYfUsGnQSUTWvhdtSbCNDGkNAiF1bitllUp1VUpxSh9r+VOtItFQjphqGd2cgiirsqVcc31XVXZ59gqyb0jqf40sPz/HNbcyux0us+Epd6PleWY+CK2mChO1O76VC8N2BGPfWMEkDN44VZKrSHkPQHJ6dPU1QiyNE5qyAf9n1npT/zTyAl2AnRXAwD+DVark4wHAQGaJzMEkVlPkoPT8ahtuTwCiV257DxBL6g+VO9fW7U+ZsGZz3yihpcJ89LaFDTEa9n15J1iv1qKkOpspBVcEOFEyUQ9vDdKYzVjApfJaOpd37oiGHpe0NB0eSwwNVTqayeo7DCNbr6RoK8HmfxFhLHWy6AGc/rBa8rULWhtTfF/hahsnxdFEDtXYkpKlHGPYXKNluQmjNp83gcy+/Bbt/6qpL3HzGFl0DDUdqfI9n+JdJxrFxl2xI8sTgN04y/n21w0/1ewAAAP//+AAHUDsGAAA=
name: pod-multi-container
spec:
containers:
Expand Down
2 changes: 1 addition & 1 deletion integration_test/testdata/policies/default-policy.rego
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ default GetOOMEventRequest := true
default GuestDetailsRequest := true
default OnlineCPUMemRequest := true
default PullImageRequest := true
default ReadStreamRequest := false
default ReadStreamRequest := true
default RemoveContainerRequest := true
default RemoveStaleVirtiofsShareMountsRequest := true
default SignalProcessRequest := true
Expand Down
4 changes: 2 additions & 2 deletions pkg/initdata/initdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func Generate(cfg *config.CocoConfig, imagePullSecrets []ImagePullSecretInfo) (s
return "", fmt.Errorf("failed to load policy file: %w", err)
}
} else {
// Use default restrictive policy (exec and log disabled)
// Use default restrictive policy (exec disabled, logs enabled)
policy = getDefaultPolicy()
}

Expand Down Expand Up @@ -244,7 +244,7 @@ default MemHotplugByProbeRequest := true
default OnlineCPUMemRequest := true
default PauseContainerRequest := true
default PullImageRequest := true
default ReadStreamRequest := false
default ReadStreamRequest := true
default RemoveContainerRequest := true
default RemoveStaleVirtiofsShareMountsRequest := true
default ReseedRandomDevRequest := true
Expand Down
29 changes: 26 additions & 3 deletions pkg/trustee/trustee.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,34 @@ func GetServiceURL(namespace, serviceName string) string {
}

func ensureNamespace(namespace string) error {
cmd := exec.Command("kubectl", "create", "namespace", namespace)
// Check if namespace exists by trying to access it (namespace-level permission)
// This is more reliable than 'kubectl get namespace' which requires cluster-level permissions
cmd := exec.Command("kubectl", "get", "serviceaccounts", "-n", namespace, "--limit=1")
output, err := cmd.CombinedOutput()
if err != nil && !strings.Contains(string(output), "AlreadyExists") {
return fmt.Errorf("failed to create namespace: %w\n%s", err, output)
if err == nil {
// Successfully accessed resources in namespace, so it exists
return nil
}

// Check if the error indicates namespace doesn't exist
outputStr := string(output)
namespaceNotFound := strings.Contains(outputStr, "NotFound") ||
strings.Contains(outputStr, "not found") ||
strings.Contains(outputStr, fmt.Sprintf("namespace \"%s\" not found", namespace))

if namespaceNotFound {
// Namespace doesn't exist, try to create it
cmd = exec.Command("kubectl", "create", "namespace", namespace)
output, err = cmd.CombinedOutput()
if err != nil && !strings.Contains(string(output), "AlreadyExists") {
return fmt.Errorf("failed to create namespace: %w\n%s", err, output)
}
return nil
}

// For any other error (e.g., Forbidden when user lacks namespace creation permissions
// but namespace exists), assume namespace exists and proceed.
// Subsequent operations will fail appropriately if the namespace truly doesn't exist.
return nil
}

Expand Down