Ensures the proxy container for the given config is running. Uses the fingerprinted container and network names from the proxy config. When `proxy_config.squid_conf` is set, writes the content to a host file and bind-mounts it into the container.
(&self, proxy_config: &ResolvedProxyConfig)
| 555 | /// When `proxy_config.squid_conf` is set, writes the content to a host file |
| 556 | /// and bind-mounts it into the container. |
| 557 | async fn ensure_proxy_container(&self, proxy_config: &ResolvedProxyConfig) -> Result<()> { |
| 558 | let container_name = proxy_config.proxy_container_name(); |
| 559 | let network_name = proxy_config.external_network_name(); |
| 560 | let host_ports_env = format!("TSK_HOST_PORTS={}", proxy_config.host_ports_env()); |
| 561 | |
| 562 | // Prepare optional squid.conf bind mount |
| 563 | let binds = if let Some(ref squid_conf_content) = proxy_config.squid_conf { |
| 564 | let fingerprint = proxy_config.fingerprint(); |
| 565 | let proxy_conf_dir = self.tsk_env.proxy_config_dir(&fingerprint); |
| 566 | std::fs::create_dir_all(&proxy_conf_dir) |
| 567 | .context("Failed to create proxy config directory")?; |
| 568 | |
| 569 | let squid_conf_path = proxy_conf_dir.join("squid.conf"); |
| 570 | std::fs::write(&squid_conf_path, squid_conf_content) |
| 571 | .context("Failed to write squid.conf")?; |
| 572 | |
| 573 | Some(vec![format!( |
| 574 | "{}:/etc/squid/squid.conf:ro", |
| 575 | squid_conf_path.display() |
| 576 | )]) |
| 577 | } else { |
| 578 | None |
| 579 | }; |
| 580 | |
| 581 | let container_config = ContainerCreateBody { |
| 582 | image: Some(PROXY_IMAGE.to_string()), |
| 583 | exposed_ports: Some(vec![PROXY_PORT.to_string()]), |
| 584 | env: Some(vec![host_ports_env]), |
| 585 | host_config: Some(HostConfig { |
| 586 | network_mode: Some(network_name), |
| 587 | extra_hosts: Some(vec!["host.docker.internal:host-gateway".to_string()]), |
| 588 | restart_policy: Some(bollard::models::RestartPolicy { |
| 589 | name: Some(bollard::models::RestartPolicyNameEnum::UNLESS_STOPPED), |
| 590 | maximum_retry_count: None, |
| 591 | }), |
| 592 | binds, |
| 593 | // Security hardening options |
| 594 | readonly_rootfs: Some(true), |
| 595 | cap_drop: Some(vec!["ALL".to_string()]), |
| 596 | cap_add: Some(vec![ |
| 597 | "NET_ADMIN".to_string(), // For iptables firewall rules |
| 598 | "SETUID".to_string(), // For su-exec to drop privileges |
| 599 | "SETGID".to_string(), // For su-exec to drop privileges |
| 600 | "CHOWN".to_string(), // For fixing tmpfs ownership at startup |
| 601 | ]), |
| 602 | security_opt: Some(vec!["no-new-privileges:true".to_string()]), |
| 603 | tmpfs: Some(HashMap::from([ |
| 604 | ("/var/cache/squid".to_string(), "size=10m".to_string()), |
| 605 | ("/var/log/squid".to_string(), "size=50m".to_string()), |
| 606 | ("/var/run/squid".to_string(), "size=1m".to_string()), |
| 607 | ])), |
| 608 | ..Default::default() |
| 609 | }), |
| 610 | ..Default::default() |
| 611 | }; |
| 612 | |
| 613 | let create_options = bollard::query_parameters::CreateContainerOptionsBuilder::default() |
| 614 | .name(&container_name) |
no test coverage detected