Skip to content

Commit

Permalink
Merge pull request #204 from ginglis13/aws-config-fips-endpoint
Browse files Browse the repository at this point in the history
host-ctr: support FIPS ECR service endpoints
  • Loading branch information
ginglis13 authored Oct 23, 2024
2 parents ae54c77 + 70a95da commit 38b66be
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 6 deletions.
37 changes: 35 additions & 2 deletions sources/api/schnauzer/src/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use serde_plain::derive_fromstr_from_deserialize;
use settings_extension_oci_defaults::OciDefaultsResourceLimitV1;
use snafu::{OptionExt, ResultExt};
use std::borrow::Borrow;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::convert::TryFrom;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
Expand Down Expand Up @@ -70,6 +70,19 @@ lazy_static! {
m.insert("us-west-2", "328549459982");
m
};

/// A set to tell us which regions have FIPS ECR endpoints.
/// https://docs.aws.amazon.com/general/latest/gr/ecr.html
static ref ECR_FIPS_REGIONS: HashSet<&'static str> = {
let mut h = HashSet::new();
h.insert("us-east-1");
h.insert("us-east-2");
h.insert("us-gov-east-1");
h.insert("us-gov-west-1");
h.insert("us-west-1");
h.insert("us-west-2");
h
};
}

/// But if there is a region that does not exist in our map (for example a new
Expand All @@ -78,6 +91,9 @@ lazy_static! {
const ECR_FALLBACK_REGION: &str = "us-east-1";
const ECR_FALLBACK_REGISTRY: &str = "328549459982";

/// Path to FIPS sysctl file.
const FIPS_ENABLED_SYSCTL_PATH: &str = "/proc/sys/crypto/fips_enabled";

lazy_static! {
/// A map to tell us which endpoint to pull updates from for a given region.
static ref TUF_ENDPOINT_MAP: HashMap<&'static str, &'static str> = {
Expand Down Expand Up @@ -519,6 +535,14 @@ pub fn tuf_prefix(
Ok(())
}

/// Utility function to determine if a variant is in FIPS mode based
/// on /proc/sys/crypto/fips_enabled.
fn fips_enabled() -> bool {
std::fs::read_to_string(FIPS_ENABLED_SYSCTL_PATH)
.map(|s| s.trim() == "1")
.unwrap_or(false)
}

/// The `metadata-prefix` helper is used to map an AWS region to the correct
/// metadata location inside of the TUF repository.
///
Expand Down Expand Up @@ -1426,7 +1450,16 @@ fn ecr_registry<S: AsRef<str>>(region: S) -> String {
match partition {
"aws-cn" => format!("{}.dkr.ecr.{}.amazonaws.com.cn", registry_id, region),
"aws-iso-e" => format!("{}.dkr.ecr.{}.cloud.adc-e.uk", registry_id, region),
_ => format!("{}.dkr.ecr.{}.amazonaws.com", registry_id, region),
_ => {
// Only inject the FIPS service endpoint if the variant is in FIPS mode and the
// region supports FIPS.
let suffix = if fips_enabled() && ECR_FIPS_REGIONS.contains(region) {
"-fips"
} else {
""
};
format!("{}.dkr.ecr{}.{}.amazonaws.com", registry_id, suffix, region)
}
}
}

Expand Down
33 changes: 29 additions & 4 deletions sources/host-ctr/cmd/host-ctr/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ import (
// Example 1: 777777777777.dkr.ecr.us-west-2.amazonaws.com/my_image:latest
// Example 2: 777777777777.dkr.ecr.cn-north-1.amazonaws.com.cn/my_image:latest
// Example 3: 777777777777.dkr.ecr.eu-isoe-west-1.cloud.adc-e.uk/my_image:latest
var ecrRegex = regexp.MustCompile(`(^[a-zA-Z0-9][a-zA-Z0-9-_]*)\.dkr\.ecr\.([a-zA-Z0-9][a-zA-Z0-9-_]*)\.(amazonaws\.com(\.cn)?|cloud\.adc-e\.uk).*`)
// Example 4: 777777777777.dkr.ecr-fips.us-west-2.amazonaws.com/my_image:latest
var ecrRegex = regexp.MustCompile(`(^[a-zA-Z0-9][a-zA-Z0-9-_]*)\.dkr\.ecr(-fips)?\.([a-zA-Z0-9][a-zA-Z0-9-_]*)\.(amazonaws\.com(\.cn)?|cloud\.adc-e\.uk).*`)

const (
// The maximum size of an image label.
Expand Down Expand Up @@ -594,21 +595,28 @@ func cleanUp(containerdSocket string, namespace string, containerID string) erro

// parseImageURISpecialRegions mimics the parsing in ecr.ParseImageURI but
// constructs the canonical ECR references while skipping certain checks.
// We only do this for special regions that are not yet supported by the aws-go-sdk.
// We only do this for special regions that are not yet supported by the aws-go-sdk and for ECR FIPS endpoints.
// Referenced source: https://github.com/awslabs/amazon-ecr-containerd-resolver/blob/a5058cf091f4fc573813a032db37a9820952f1f9/ecr/ref.go#L70-L71
func parseImageURISpecialRegions(input string) (ecr.ECRSpec, error) {
ecrRefPrefixMapping := map[string]string{
"ap-southeast-5": "ecr.aws/arn:aws:ecr:ap-southeast-5:",
"eu-isoe-west-1": "ecr.aws/arn:aws-iso-e:ecr:eu-isoe-west-1:",
}
// A set of the currently supported FIPS regions for ECR: https://docs.aws.amazon.com/general/latest/gr/ecr.html
fipsSupportedEcrRegionSet := map[string]bool{
"us-east-1": true,
"us-east-2": true,
"us-west-1": true,
"us-west-2": true,
"us-gov-east-1": true,
"us-gov-west-1": true,
}
// Matching on account, region
matches := ecrRegex.FindStringSubmatch(input)
if len(matches) < 3 {
return ecr.ECRSpec{}, fmt.Errorf("invalid image URI: %s", input)
}
account := matches[1]
region := matches[2]

// Need to include the full repository path and the imageID (e.g. /eks/image-name:tag)
tokens := strings.SplitN(input, "/", 2)
if len(tokens) != 2 {
Expand All @@ -627,6 +635,23 @@ func parseImageURISpecialRegions(input string) (ecr.ECRSpec, error) {
return ecr.ECRSpec{}, errors.New("incomplete reference provided")
}

// Return early if the FIPS endpoint is being used. amazon-ecr-containerd-resolver doesn't yet support FIPS urls:
// https://github.com/awslabs/amazon-ecr-containerd-resolver/blob/7b72333e780f5a5168936eae79fb89448e2f2a8f/ecr/ref.go#L43
// The ecr-prefix helper for admin and control host containers will have already accounted for setting this endpoint
// if the region has FIPS support.
if matches[2] == "-fips" {
region := matches[3]
_, isFips := fipsSupportedEcrRegionSet[region]
if !isFips {
return ecr.ECRSpec{}, fmt.Errorf("%s: %s", "invalid FIPS region", region)
}
ecrRefPrefix := fmt.Sprintf("ecr.aws/arn:aws:ecr-fips:%s:", region)
return ecr.ParseRef(fmt.Sprintf("%s%s:repository/%s", ecrRefPrefix, account, fullRepoPath))
}

// The provided URI does not specify the FIPS endpoint, and the second match is the region.
region := matches[2]

// Get the ECR image reference prefix from the AWS region
ecrRefPrefix, ok := ecrRefPrefixMapping[region]
if !ok {
Expand Down
12 changes: 12 additions & 0 deletions sources/host-ctr/cmd/host-ctr/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,18 @@ func TestFetchECRRef(t *testing.T) {
false,
"ecr.aws/arn:aws-us-gov:ecr:us-gov-west-1:111111111111:repository/bottlerocket/container:1.2.3",
},
{
"Parse FIPS region for normal use-cases",
"111111111111.dkr.ecr-fips.us-west-2.amazonaws.com/bottlerocket/container:1.2.3",
false,
"ecr.aws/arn:aws:ecr-fips:us-west-2:111111111111:repository/bottlerocket/container:1.2.3",
},
{
"Fail for region that does not have FIPS support",
"111111111111.dkr.ecr-fips.ca-central-1.amazonaws.com/bottlerocket/container:1.2.3",
true,
"",
},
{
"Fail for invalid region",
"111111111111.dkr.ecr.outer-space.amazonaws.com/bottlerocket/container:1.2.3",
Expand Down

0 comments on commit 38b66be

Please sign in to comment.