Skip to content

Commit

Permalink
use cobra flags
Browse files Browse the repository at this point in the history
  • Loading branch information
cpanato committed Jan 21, 2025
1 parent 7fd1a2c commit 4609372
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 66 deletions.
39 changes: 18 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,31 @@ Alternatively, you can also build from source by cloning the repo and running `g
`incert` supports the following flags:

```shell
-ca-certs-file string
The path to the local CA certificates file
-ca-certs-image-url string
The URL of an image to extract the CA certificates from
-dest-image-url string
The URL of the image to push the modified image to
-image-cert-path string
The path to the certificate file in the image (optional) (default "/etc/ssl/certs/ca-certificates.crt")
-image-url string
The URL of the image to append the CA certificates to
-output-certs-path string
Output the (appended) certificates file from the image to a local file (optional)
-owner-group-id int
The group ID of the owner of the certificate file in the image (optional)
-owner-user-id int
The user ID of the owner of the certificate file in the image (optional)
-platform string
The platform to build the image for (default "linux/amd64")
-replace-certs
Replace the certificates in the certificate file instead of appending them
Appends CA certificates to Docker images and pushes the modified image to a specified registry.

Usage:
incert [flags]

Flags:
--ca-certs-file string The path to the local CA certificates file
--ca-certs-image-url string The URL of an image to extract the CA certificates from
--dest-image-url string The URL of the image to push the modified image to
-h, --help help for incert
--image-cert-path string The path to the certificate file in the image (optional) (default "/etc/ssl/certs/ca-certificates.crt")
--image-url string The URL of the image to append the CA certificates to
--output-certs-path string Output the (appended) certificates file from the image to a local file (optional)
--owner-group-id int The group ID of the owner of the certificate file in the image (optional)
--owner-user-id int The user ID of the owner of the certificate file in the image (optional)
--platform string The platform to build the image for (default "linux/amd64")
--replace-certs Replace the certificates in the certificate file instead of appending them
```

## Example

To append a corporate CA certificate to an image, use the following command:

```bash
$ incert -image-url=mycompany/myimage:latest -ca-certs-file=/path/to/cacerts.pem -dest-image-url=myregistry/myimage:latest
$ incert --image-url=mycompany/myimage:latest --ca-certs-file=/path/to/cacerts.pem --dest-image-url=myregistry/myimage:latest
```

This will append the certificates in `/path/to/cacerts.pem` to the `mycompany/myimage:latest` image and push the modified image to `myregistry/myimage:latest`.
Expand Down
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ go 1.23.0

toolchain go1.23.5

require github.com/google/go-containerregistry v0.20.3
require (
github.com/google/go-containerregistry v0.20.3
github.com/spf13/cobra v1.8.1
)

require (
github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
Expand All @@ -17,6 +20,7 @@ require (
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/vbatts/tar-split v0.11.6 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
Expand Down
44 changes: 44 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,22 +1,44 @@
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/stargz-snapshotter/estargz v0.16.3 h1:7evrXtoh1mSbGj/pfRccTampEyKpjpOnS3CyiV1Ebr8=
github.com/containerd/stargz-snapshotter/estargz v0.16.3/go.mod h1:uyr4BfYfOj3G9WBVE8cOlQmXAbPN9VEQpBBeJIuOipU=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v27.5.0+incompatible h1:aMphQkcGtpHixwwhAXJT1rrK/detk2JIvDaFkLctbGM=
github.com/docker/cli v27.5.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v27.5.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-containerregistry v0.20.3 h1:oNx7IdTI936V8CQRveCjaxOiegWwvM7kqkbXTpyiovI=
github.com/google/go-containerregistry v0.20.3/go.mod h1:w00pIgBRDVUDFM6bq+Qx8lwNWK+cxgCuX1vd3PIBDNI=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
Expand All @@ -25,19 +47,41 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/urfave/cli v1.22.15/go.mod h1:wSan1hmo5zeyLGBjRJbzRTNk8gwoYa2B9n4q9dmRIc0=
github.com/vbatts/tar-split v0.11.6 h1:4SjTW5+PU11n6fZenf2IPoV8/tz3AaYHMWjf23envGs=
github.com/vbatts/tar-split v0.11.6/go.mod h1:dqKNtesIOr2j2Qv3W/cHjnvk9I8+G7oAkFDFN6TCBEI=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q=
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0=
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
106 changes: 62 additions & 44 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import (
"archive/tar"
"bytes"
"encoding/pem"
"flag"
"errors"
"fmt"
"io"
"log"
"os"
"strings"

"github.com/spf13/cobra"

"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
Expand All @@ -38,99 +40,113 @@ var (
)

func init() {
flag.StringVar(&imageURL, "image-url", "", "The URL of the image to append the CA certificates to")
flag.StringVar(&caCertFile, "ca-certs-file", "", "The path to the local CA certificates file")
flag.StringVar(&caCertsImageURL, "ca-certs-image-url", "", "The URL of an image to extract the CA certificates from")
flag.StringVar(&destImageURL, "dest-image-url", "", "The URL of the image to push the modified image to")
flag.StringVar(&platformStr, "platform", "linux/amd64", "The platform to build the image for")

flag.StringVar(&imageCertPath, "image-cert-path", "/etc/ssl/certs/ca-certificates.crt", "The path to the certificate file in the image (optional)")
flag.IntVar(&ownerUserID, "owner-user-id", 0, "The user ID of the owner of the certificate file in the image (optional)")
flag.IntVar(&ownerGroupID, "owner-group-id", 0, "The group ID of the owner of the certificate file in the image (optional)")
flag.StringVar(&outputCerts, "output-certs-path", "", "Output the (appended) certificates file from the image to a local file (optional)")
flag.BoolVar(&replaceCerts, "replace-certs", false, "Replace the certificates in the certificate file instead of appending them")
rootCmd.Flags().StringVar(&imageURL, "image-url", "", "The URL of the image to append the CA certificates to")
rootCmd.Flags().StringVar(&caCertFile, "ca-certs-file", "", "The path to the local CA certificates file")
rootCmd.Flags().StringVar(&caCertsImageURL, "ca-certs-image-url", "", "The URL of an image to extract the CA certificates from")
rootCmd.Flags().StringVar(&destImageURL, "dest-image-url", "", "The URL of the image to push the modified image to")
rootCmd.Flags().StringVar(&platformStr, "platform", "linux/amd64", "The platform to build the image for")

rootCmd.Flags().StringVar(&imageCertPath, "image-cert-path", "/etc/ssl/certs/ca-certificates.crt", "The path to the certificate file in the image (optional)")
rootCmd.Flags().IntVar(&ownerUserID, "owner-user-id", 0, "The user ID of the owner of the certificate file in the image (optional)")
rootCmd.Flags().IntVar(&ownerGroupID, "owner-group-id", 0, "The group ID of the owner of the certificate file in the image (optional)")
rootCmd.Flags().StringVar(&outputCerts, "output-certs-path", "", "Output the (appended) certificates file from the image to a local file (optional)")
rootCmd.Flags().BoolVar(&replaceCerts, "replace-certs", false, "Replace the certificates in the certificate file instead of appending them")

_ = rootCmd.MarkFlagRequired("image-url")
_ = rootCmd.MarkFlagRequired("dest-image-url")
}

func usage() {
flag.Usage()
os.Exit(1)
func main() {
if err := rootCmd.Execute(); err != nil {
os.Exit(1)
}
}

func main() {
var rootCmd = &cobra.Command{
Use: "incert",
Short: "Appends CA certificates to Docker images and pushes the modified image to a specified registry.",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
return do(cmd, args)
},
}

// Fetch the remote image
func fetchImage(imageURL string, platform v1.Platform) (v1.Image, error) {
ref, err := name.ParseReference(imageURL)
if err != nil {
return nil, err
}
img, err := remote.Image(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain), remote.WithPlatform((platform)))
if err != nil {
return nil, err
}
return img, nil
}

func do(_ *cobra.Command, _ []string) error {
var platform v1.Platform
flag.Parse()

if imageURL == "" || destImageURL == "" || (caCertFile == "" && caCertsImageURL == "") {
usage()
if caCertFile == "" && caCertsImageURL == "" {
return errors.New("either --ca-certs-file or --ca-certs-image-url must be provided")
}

if platformStr != "" {
p, err := v1.ParsePlatform(platformStr)
if err != nil {
log.Fatalf("Failed to parse platform: %s", err)
return fmt.Errorf("Failed to parse platform: %s", err)
}
platform = *p
}

// Get the cert bytes
caCertBytes, err := getCertBytes(platform)
if err != nil {
log.Fatalf("Failed to get certificate bytes: %s", err)
return fmt.Errorf("Failed to get certificate bytes: %s", err)
}

// Sanity check to make sure the caCertBytes are actually a list of pem-encoded certificates
block, _ := pem.Decode(caCertBytes)
if block == nil || block.Type != "CERTIFICATE" {
log.Fatalf("Failed to find any certificates in %s", caCertFile)
return fmt.Errorf("Failed to find any certificates in %s", caCertFile)
}

img, err := fetchImage(imageURL, platform)
if err != nil {
log.Fatalf("Failed to fetch image %s: %s\n", imageURL, err)
return fmt.Errorf("Failed to fetch image %s: %s\n", imageURL, err)
}

newImg, err := newImage(img, caCertBytes)
if err != nil {
log.Fatalf("Failed to create new image: %s\n", err)
return fmt.Errorf("Failed to create new image: %s\n", err)
}

if outputCerts != "" {
if err := os.WriteFile(outputCerts, caCertBytes, 0644); err != nil {
log.Fatalf("Failed to write certificates to file %s: %s.\n", outputCerts, err)
return fmt.Errorf("Failed to write certificates to file %s: %s.\n", outputCerts, err)
}
}

newRef, err := name.ParseReference(destImageURL)
if err != nil {
log.Fatalf("Failed to parse destination image URL %s: %s\n", destImageURL, err)
return fmt.Errorf("Failed to parse destination image URL %s: %s\n", destImageURL, err)
}

// Push the modified image back to the registry
err = remote.Write(newRef, newImg, remote.WithAuthFromKeychain(authn.DefaultKeychain))
if err != nil {
log.Fatalf("Failed to push modified image %s: %s\n", newRef.String(), err)
return fmt.Errorf("Failed to push modified image %s: %s\n", newRef.String(), err)
}

fmt.Fprintf(os.Stderr, "Successfully appended CA certificates to image %s\n", newRef.String())
h, err := newImg.Digest()
if err != nil {
log.Fatalf("Failed to get digest of image %s: %s\n", newRef.String(), err)
return fmt.Errorf("Failed to get digest of image %s: %s\n", newRef.String(), err)
}

fmt.Printf("%s@sha256:%s\n", newRef.String(), h.Hex)
}

// Fetch the remote image
func fetchImage(imageURL string, platform v1.Platform) (v1.Image, error) {
ref, err := name.ParseReference(imageURL)
if err != nil {
return nil, err
}
img, err := remote.Image(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain), remote.WithPlatform((platform)))
if err != nil {
return nil, err
}
return img, nil
return nil
}

func getCertBytes(platform v1.Platform) ([]byte, error) {
Expand All @@ -139,21 +155,22 @@ func getCertBytes(platform v1.Platform) ([]byte, error) {
// Read the contents of the local CA certificates file
caCertBytes, err := os.ReadFile(caCertFile)
if err != nil {
log.Fatalf("Failed to read CA certificates file %s: %s\n", caCertFile, err)
return []byte{}, fmt.Errorf("Failed to read CA certificates file %s: %s\n", caCertFile, err)
}

// Sanity check to make sure the caCertBytes are actually a list of pem-encoded certificates
block, _ := pem.Decode(caCertBytes)
if block == nil || block.Type != "CERTIFICATE" {
log.Fatalf("Failed to find any certificates in %s", caCertFile)
return []byte{}, fmt.Errorf("Failed to find any certificates in %s", caCertFile)
}
return caCertBytes, nil
} else {
// Fetch the remote image and its manifest
img, err := fetchImage(caCertsImageURL, platform)
if err != nil {
log.Fatalf("Failed to fetch image %s: %s\n", caCertsImageURL, err)
return []byte{}, fmt.Errorf("Failed to fetch image %s: %s\n", caCertsImageURL, err)
}

return extractCACerts(img)
}
}
Expand All @@ -173,6 +190,7 @@ func extractCACerts(img v1.Image) ([]byte, error) {
return io.ReadAll(tr)
}
}

return nil, fmt.Errorf("failed to find %s in remote image", imageCertPath)
}

Expand All @@ -191,7 +209,7 @@ func newImage(old v1.Image, caCertBytes []byte) (v1.Image, error) {
// Create a new tar file with the modified ca-certificates file
buf := bytes.Buffer{}
newTar := tar.NewWriter(&buf)
newTar.WriteHeader(&tar.Header{
_ = newTar.WriteHeader(&tar.Header{
Name: imageCertPath,
Mode: 0644,
Size: int64(len(newCaCertBytes)),
Expand Down

0 comments on commit 4609372

Please sign in to comment.