Skip to content

Hardening a Ruby Application

  1. Generate Hardening Manifest Resources
  2. Find the upstream project source (i.e. github) and identify the desired release, Ruby version and Gemfile
  3. Within the Gemfile, find the gem name: gemspec :name => "jekyll"
  4. Clone https://repo1.dso.mil/dsop/container-hardening-tools/proof-of-concept/resource_scripts
  5. Paste the gem name ("jekyll" in this instance) into the resource_scripts ./requirements_files/gem-packages.txt
  6. From where you cloned resource_scripts, execute python3 generate_hardening_manifest.py -g
  7. The generate_hardening_manifest.py script will read gem-packages.txt and download .gem files from RubyGems.org and will finally generate a manifest at ./hardening_manifest/hardening_manifest.yaml.

  8. Open ./hardening_manifest/hardening_manifest.yaml and copy the resources to your project's hardening_manifest.yaml.

  9. Review the resource list for accuracy against the gem's RubyGems.org page (see Jekyll's runtime depdencies).
  10. Use the fetch tool to read your project's hardening_manifest.yaml, download the resources and validate checksums.
  11. Update your Dockerfile to use an Iron Bank Ruby base image, install gcc, and then COPY all *.gem files into the image build, and then use gem install:
ARG PACKAGE_DIR="."
COPY ["${PACKAGE_DIR}/*.gem", "/opt/"]

This example comes from https://repo1.dso.mil/dsop/opensource/fluentd/fluentd/-/blob/development/Dockerfile

RUN yum update -y && \
    yum install -y make gcc bzip2 && \
    gem install --local -N \
        /opt/concurrent-ruby.gem \
        /opt/strptime.gem \
        /opt/sigdump.gem \
        /opt/tzinfo.gem \
        /opt/tzinfo-data.gem \
        /opt/bigdecimal.gem \
        /opt/cool.io.gem \
        /opt/http_parser.gem \
        /opt/json.gem \
        /opt/msgpack.gem \
        /opt/oj.gem \
        /opt/webrick.gem \
        /opt/yajl-ruby.gem \
        /opt/serverengine.gem \
        /opt/fluentd.gem

Note (Pulling in dependancies using RubyGems)

IronBank has implemented a new method of pulling in Ruby dependancies. The RubyGems repository is now mirrored by our Nexus proxy. Instead of collecting and individually placing dependancy files in the hardening manifest, developers are now able to use a Gemfile and install with the bundle install command just as you would locally.

Warning: we caution users against blindly using bundler as it does not respect ruby packages installed in parent images.

For individuals using sources other than RubyGems to pull Ruby packages, you will need to revert back to using the older method which would require you individually collect the packages and place them in the hardening manifest.

Testing

Test executing the entrypoint (if applicable), comparing its output to the upstream image. If the image provides multiple tools, then attach to a running container and execute each tool. For either case, we want to verify that each tool/app works without exiting on missing dependencies.

Once your build completes you can merge to development and start working on justifications if necessary.

Example Projects