diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go
index 6c74b8a9b4..d0562e7f08 100644
--- a/cmd/podman/shared/create.go
+++ b/cmd/podman/shared/create.go
@@ -26,7 +26,6 @@ import (
 	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/go-connections/nat"
 	"github.com/docker/go-units"
-	"github.com/opencontainers/selinux/go-selinux/label"
 	"github.com/opentracing/opentracing-go"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
@@ -195,72 +194,6 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
 	return ctr, createConfig, nil
 }
 
-func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string, runtime *libpod.Runtime) error {
-	var (
-		labelOpts []string
-	)
-
-	if config.PidMode.IsHost() {
-		labelOpts = append(labelOpts, label.DisableSecOpt()...)
-	} else if config.PidMode.IsContainer() {
-		ctr, err := runtime.LookupContainer(config.PidMode.Container())
-		if err != nil {
-			return errors.Wrapf(err, "container %q not found", config.PidMode.Container())
-		}
-		secopts, err := label.DupSecOpt(ctr.ProcessLabel())
-		if err != nil {
-			return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
-		}
-		labelOpts = append(labelOpts, secopts...)
-	}
-
-	if config.IpcMode.IsHost() {
-		labelOpts = append(labelOpts, label.DisableSecOpt()...)
-	} else if config.IpcMode.IsContainer() {
-		ctr, err := runtime.LookupContainer(config.IpcMode.Container())
-		if err != nil {
-			return errors.Wrapf(err, "container %q not found", config.IpcMode.Container())
-		}
-		secopts, err := label.DupSecOpt(ctr.ProcessLabel())
-		if err != nil {
-			return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
-		}
-		labelOpts = append(labelOpts, secopts...)
-	}
-
-	for _, opt := range securityOpts {
-		if opt == "no-new-privileges" {
-			config.NoNewPrivs = true
-		} else {
-			con := strings.SplitN(opt, "=", 2)
-			if len(con) != 2 {
-				return fmt.Errorf("invalid --security-opt 1: %q", opt)
-			}
-
-			switch con[0] {
-			case "label":
-				labelOpts = append(labelOpts, con[1])
-			case "apparmor":
-				config.ApparmorProfile = con[1]
-			case "seccomp":
-				config.SeccompProfilePath = con[1]
-			default:
-				return fmt.Errorf("invalid --security-opt 2: %q", opt)
-			}
-		}
-	}
-
-	if config.SeccompProfilePath == "" {
-		var err error
-		config.SeccompProfilePath, err = libpod.DefaultSeccompPath()
-		if err != nil {
-			return err
-		}
-	}
-	config.LabelOpts = labelOpts
-	return nil
-}
-
 func configureEntrypoint(c *GenericCLIResults, data *inspect.ImageData) []string {
 	entrypoint := []string{}
 	if c.IsSet("entrypoint") {
@@ -348,11 +281,6 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
 		rootfs = c.InputArgs[0]
 	}
 
-	sysctl, err := validateSysctl(c.StringSlice("sysctl"))
-	if err != nil {
-		return nil, errors.Wrapf(err, "invalid value for sysctl")
-	}
-
 	if c.String("memory") != "" {
 		memoryLimit, err = units.RAMInBytes(c.String("memory"))
 		if err != nil {
@@ -691,61 +619,96 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
 		pidsLimit = 0
 	}
 
+	pid := &cc.PidConfig{
+		PidMode: pidMode,
+	}
+	ipc := &cc.IpcConfig{
+		IpcMode: ipcMode,
+	}
+
+	cgroup := &cc.CgroupConfig{
+		Cgroups:      c.String("cgroups"),
+		Cgroupns:     c.String("cgroupns"),
+		CgroupParent: c.String("cgroup-parent"),
+		CgroupMode:   cgroupMode,
+	}
+
+	userns := &cc.UserConfig{
+		GroupAdd:   c.StringSlice("group-add"),
+		IDMappings: idmappings,
+		UsernsMode: usernsMode,
+		User:       user,
+	}
+
+	uts := &cc.UtsConfig{
+		UtsMode:  utsMode,
+		NoHosts:  c.Bool("no-hosts"),
+		HostAdd:  c.StringSlice("add-host"),
+		Hostname: c.String("hostname"),
+	}
+
+	net := &cc.NetworkConfig{
+		DNSOpt:       c.StringSlice("dns-opt"),
+		DNSSearch:    c.StringSlice("dns-search"),
+		DNSServers:   c.StringSlice("dns"),
+		HTTPProxy:    c.Bool("http-proxy"),
+		MacAddress:   c.String("mac-address"),
+		Network:      network,
+		NetMode:      netMode,
+		IPAddress:    c.String("ip"),
+		Publish:      c.StringSlice("publish"),
+		PublishAll:   c.Bool("publish-all"),
+		PortBindings: portBindings,
+	}
+
+	sysctl, err := validateSysctl(c.StringSlice("sysctl"))
+	if err != nil {
+		return nil, errors.Wrapf(err, "invalid value for sysctl")
+	}
+
+	secConfig := &cc.SecurityConfig{
+		CapAdd:         c.StringSlice("cap-add"),
+		CapDrop:        c.StringSlice("cap-drop"),
+		Privileged:     c.Bool("privileged"),
+		ReadOnlyRootfs: c.Bool("read-only"),
+		ReadOnlyTmpfs:  c.Bool("read-only-tmpfs"),
+		Sysctl:         sysctl,
+	}
+
+	if err := secConfig.SetLabelOpts(runtime, pid, ipc); err != nil {
+		return nil, err
+	}
+	if err := secConfig.SetSecurityOpts(runtime, c.StringArray("security-opt")); err != nil {
+		return nil, err
+	}
+
 	config := &cc.CreateConfig{
 		Annotations:       annotations,
 		BuiltinImgVolumes: ImageVolumes,
 		ConmonPidFile:     c.String("conmon-pidfile"),
 		ImageVolumeType:   c.String("image-volume"),
-		CapAdd:            c.StringSlice("cap-add"),
-		CapDrop:           c.StringSlice("cap-drop"),
 		CidFile:           c.String("cidfile"),
-		Cgroupns:          c.String("cgroupns"),
-		Cgroups:           c.String("cgroups"),
-		CgroupParent:      c.String("cgroup-parent"),
 		Command:           command,
 		UserCommand:       userCommand,
 		Detach:            c.Bool("detach"),
 		Devices:           c.StringSlice("device"),
-		DNSOpt:            c.StringSlice("dns-opt"),
-		DNSSearch:         c.StringSlice("dns-search"),
-		DNSServers:        c.StringSlice("dns"),
 		Entrypoint:        entrypoint,
 		Env:               env,
 		// ExposedPorts:   ports,
-		GroupAdd:    c.StringSlice("group-add"),
-		Hostname:    c.String("hostname"),
-		HostAdd:     c.StringSlice("add-host"),
-		HTTPProxy:   c.Bool("http-proxy"),
-		NoHosts:     c.Bool("no-hosts"),
-		IDMappings:  idmappings,
 		Init:        c.Bool("init"),
 		InitPath:    c.String("init-path"),
 		Image:       imageName,
 		ImageID:     imageID,
 		Interactive: c.Bool("interactive"),
 		// IP6Address:     c.String("ipv6"), // Not implemented yet - needs CNI support for static v6
-		IPAddress: c.String("ip"),
-		Labels:    labels,
+		Labels: labels,
 		// LinkLocalIP:    c.StringSlice("link-local-ip"), // Not implemented yet
 		LogDriver:    logDriver,
 		LogDriverOpt: c.StringSlice("log-opt"),
-		MacAddress:   c.String("mac-address"),
 		Name:         c.String("name"),
-		Network:      network,
 		// NetworkAlias:   c.StringSlice("network-alias"), // Not implemented - does this make sense in Podman?
-		IpcMode:        ipcMode,
-		NetMode:        netMode,
-		UtsMode:        utsMode,
-		PidMode:        pidMode,
-		CgroupMode:     cgroupMode,
-		Pod:            podName,
-		Privileged:     c.Bool("privileged"),
-		Publish:        c.StringSlice("publish"),
-		PublishAll:     c.Bool("publish-all"),
-		PortBindings:   portBindings,
-		Quiet:          c.Bool("quiet"),
-		ReadOnlyRootfs: c.Bool("read-only"),
-		ReadOnlyTmpfs:  c.Bool("read-only-tmpfs"),
+		Pod:   podName,
+		Quiet: c.Bool("quiet"),
 		Resources: cc.CreateResourceConfig{
 			BlkioWeight:       blkioWeight,
 			BlkioWeightDevice: c.StringSlice("blkio-weight-device"),
@@ -774,30 +737,27 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
 		},
 		RestartPolicy: c.String("restart"),
 		Rm:            c.Bool("rm"),
+		Security:      *secConfig,
 		StopSignal:    stopSignal,
 		StopTimeout:   c.Uint("stop-timeout"),
-		Sysctl:        sysctl,
 		Systemd:       systemd,
 		Tmpfs:         c.StringArray("tmpfs"),
 		Tty:           tty,
-		User:          user,
-		UsernsMode:    usernsMode,
 		MountsFlag:    c.StringArray("mount"),
 		Volumes:       c.StringArray("volume"),
 		WorkDir:       workDir,
 		Rootfs:        rootfs,
 		VolumesFrom:   c.StringSlice("volumes-from"),
 		Syslog:        c.Bool("syslog"),
-	}
 
-	if config.Privileged {
-		config.LabelOpts = label.DisableSecOpt()
-	} else {
-		if err := parseSecurityOpt(config, c.StringArray("security-opt"), runtime); err != nil {
-			return nil, err
-		}
+		Pid:     *pid,
+		Ipc:     *ipc,
+		Cgroup:  *cgroup,
+		User:    *userns,
+		Uts:     *uts,
+		Network: *net,
 	}
-	config.SecurityOpts = c.StringArray("security-opt")
+
 	warnings, err := verifyContainerResources(config, false)
 	if err != nil {
 		return nil, err
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go
index 6648edc821..85f93ed3e7 100644
--- a/pkg/adapter/pods.go
+++ b/pkg/adapter/pods.go
@@ -666,55 +666,55 @@ func getPodPorts(containers []v1.Container) []ocicni.PortMapping {
 	return infraPorts
 }
 
-func setupSecurityContext(containerConfig *createconfig.CreateConfig, containerYAML v1.Container) {
+func setupSecurityContext(securityConfig *createconfig.SecurityConfig, userConfig *createconfig.UserConfig, containerYAML v1.Container) {
 	if containerYAML.SecurityContext == nil {
 		return
 	}
 	if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil {
-		containerConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem
+		securityConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem
 	}
 	if containerYAML.SecurityContext.Privileged != nil {
-		containerConfig.Privileged = *containerYAML.SecurityContext.Privileged
+		securityConfig.Privileged = *containerYAML.SecurityContext.Privileged
 	}
 
 	if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil {
-		containerConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation
+		securityConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation
 	}
 
 	if seopt := containerYAML.SecurityContext.SELinuxOptions; seopt != nil {
 		if seopt.User != "" {
-			containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=user:%s", seopt.User))
-			containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("user:%s", seopt.User))
+			securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=user:%s", seopt.User))
+			securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("user:%s", seopt.User))
 		}
 		if seopt.Role != "" {
-			containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=role:%s", seopt.Role))
-			containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("role:%s", seopt.Role))
+			securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=role:%s", seopt.Role))
+			securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("role:%s", seopt.Role))
 		}
 		if seopt.Type != "" {
-			containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=type:%s", seopt.Type))
-			containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("type:%s", seopt.Type))
+			securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=type:%s", seopt.Type))
+			securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("type:%s", seopt.Type))
 		}
 		if seopt.Level != "" {
-			containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=level:%s", seopt.Level))
-			containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("level:%s", seopt.Level))
+			securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=level:%s", seopt.Level))
+			securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("level:%s", seopt.Level))
 		}
 	}
 	if caps := containerYAML.SecurityContext.Capabilities; caps != nil {
 		for _, capability := range caps.Add {
-			containerConfig.CapAdd = append(containerConfig.CapAdd, string(capability))
+			securityConfig.CapAdd = append(securityConfig.CapAdd, string(capability))
 		}
 		for _, capability := range caps.Drop {
-			containerConfig.CapDrop = append(containerConfig.CapDrop, string(capability))
+			securityConfig.CapDrop = append(securityConfig.CapDrop, string(capability))
 		}
 	}
 	if containerYAML.SecurityContext.RunAsUser != nil {
-		containerConfig.User = fmt.Sprintf("%d", *containerYAML.SecurityContext.RunAsUser)
+		userConfig.User = fmt.Sprintf("%d", *containerYAML.SecurityContext.RunAsUser)
 	}
 	if containerYAML.SecurityContext.RunAsGroup != nil {
-		if containerConfig.User == "" {
-			containerConfig.User = "0"
+		if userConfig.User == "" {
+			userConfig.User = "0"
 		}
-		containerConfig.User = fmt.Sprintf("%s:%d", containerConfig.User, *containerYAML.SecurityContext.RunAsGroup)
+		userConfig.User = fmt.Sprintf("%s:%d", userConfig.User, *containerYAML.SecurityContext.RunAsGroup)
 	}
 }
 
@@ -722,6 +722,13 @@ func setupSecurityContext(containerConfig *createconfig.CreateConfig, containerY
 func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, runtime *libpod.Runtime, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID string) (*createconfig.CreateConfig, error) {
 	var (
 		containerConfig createconfig.CreateConfig
+		pidConfig       createconfig.PidConfig
+		networkConfig   createconfig.NetworkConfig
+		cgroupConfig    createconfig.CgroupConfig
+		utsConfig       createconfig.UtsConfig
+		ipcConfig       createconfig.IpcConfig
+		userConfig      createconfig.UserConfig
+		securityConfig  createconfig.SecurityConfig
 	)
 
 	// The default for MemorySwappiness is -1, not 0
@@ -737,15 +744,15 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
 
 	imageData, _ := newImage.Inspect(ctx)
 
-	containerConfig.User = "0"
+	userConfig.User = "0"
 	if imageData != nil {
-		containerConfig.User = imageData.Config.User
+		userConfig.User = imageData.Config.User
 	}
 
-	setupSecurityContext(&containerConfig, containerYAML)
+	setupSecurityContext(&securityConfig, &userConfig, containerYAML)
 
 	var err error
-	containerConfig.SeccompProfilePath, err = libpod.DefaultSeccompPath()
+	containerConfig.Security.SeccompProfilePath, err = libpod.DefaultSeccompPath()
 	if err != nil {
 		return nil, err
 	}
@@ -768,20 +775,28 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
 	containerConfig.StopSignal = 15
 
 	// If the user does not pass in ID mappings, just set to basics
-	if containerConfig.IDMappings == nil {
-		containerConfig.IDMappings = &storage.IDMappingOptions{}
+	if userConfig.IDMappings == nil {
+		userConfig.IDMappings = &storage.IDMappingOptions{}
 	}
 
-	containerConfig.NetMode = ns.NetworkMode(namespaces["net"])
-	containerConfig.IpcMode = ns.IpcMode(namespaces["ipc"])
-	containerConfig.UtsMode = ns.UTSMode(namespaces["uts"])
+	networkConfig.NetMode = ns.NetworkMode(namespaces["net"])
+	ipcConfig.IpcMode = ns.IpcMode(namespaces["ipc"])
+	utsConfig.UtsMode = ns.UTSMode(namespaces["uts"])
 	// disabled in code review per mheon
 	//containerConfig.PidMode = ns.PidMode(namespaces["pid"])
-	containerConfig.UsernsMode = ns.UsernsMode(namespaces["user"])
+	userConfig.UsernsMode = ns.UsernsMode(namespaces["user"])
 	if len(containerConfig.WorkDir) == 0 {
 		containerConfig.WorkDir = "/"
 	}
 
+	containerConfig.Pid = pidConfig
+	containerConfig.Network = networkConfig
+	containerConfig.Uts = utsConfig
+	containerConfig.Ipc = ipcConfig
+	containerConfig.Cgroup = cgroupConfig
+	containerConfig.User = userConfig
+	containerConfig.Security = securityConfig
+
 	// Set default environment variables and incorporate data from image, if necessary
 	envs := shared.EnvVariablesFromData(imageData)
 
diff --git a/pkg/spec/config_linux_cgo.go b/pkg/spec/config_linux_cgo.go
index a1527752ae..c471564563 100644
--- a/pkg/spec/config_linux_cgo.go
+++ b/pkg/spec/config_linux_cgo.go
@@ -10,7 +10,7 @@ import (
 	seccomp "github.com/seccomp/containers-golang"
 )
 
-func getSeccompConfig(config *CreateConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
+func getSeccompConfig(config *SecurityConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
 	var seccompConfig *spec.LinuxSeccomp
 	var err error
 
diff --git a/pkg/spec/config_linux_nocgo.go b/pkg/spec/config_linux_nocgo.go
index 10329ff3bf..8d720b6d47 100644
--- a/pkg/spec/config_linux_nocgo.go
+++ b/pkg/spec/config_linux_nocgo.go
@@ -6,6 +6,6 @@ import (
 	spec "github.com/opencontainers/runtime-spec/specs-go"
 )
 
-func getSeccompConfig(config *CreateConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
+func getSeccompConfig(config *SecurityConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
 	return nil, nil
 }
diff --git a/pkg/spec/config_unsupported.go b/pkg/spec/config_unsupported.go
index 1604148786..a2c7f44167 100644
--- a/pkg/spec/config_unsupported.go
+++ b/pkg/spec/config_unsupported.go
@@ -8,7 +8,7 @@ import (
 	"github.com/pkg/errors"
 )
 
-func getSeccompConfig(config *CreateConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
+func getSeccompConfig(config *SecurityConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
 	return nil, errors.New("function not supported on non-linux OS's")
 }
 func addDevice(g *generate.Generator, device string) error {
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index e054b3b133..244a8d1cdd 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -1,7 +1,6 @@
 package createconfig
 
 import (
-	"net"
 	"os"
 	"strconv"
 	"strings"
@@ -12,7 +11,6 @@ import (
 	"github.com/containers/libpod/libpod/define"
 	"github.com/containers/libpod/pkg/namespaces"
 	"github.com/containers/storage"
-	"github.com/cri-o/ocicni/pkg/ocicni"
 	"github.com/docker/go-connections/nat"
 	spec "github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/opencontainers/runtime-tools/generate"
@@ -55,89 +53,126 @@ type CreateResourceConfig struct {
 	Ulimit            []string //ulimit
 }
 
-// CreateConfig is a pre OCI spec structure.  It represents user input from varlink or the CLI
-type CreateConfig struct {
-	Annotations        map[string]string
-	Args               []string
+// PidConfig configures the pid namespace for the container
+type PidConfig struct {
+	PidMode namespaces.PidMode //pid
+}
+
+// IpcConfig configures the ipc namespace for the container
+type IpcConfig struct {
+	IpcMode namespaces.IpcMode //ipc
+}
+
+// CgroupConfig configures the cgroup namespace for the container
+type CgroupConfig struct {
+	Cgroups      string
+	Cgroupns     string
+	CgroupParent string                // cgroup-parent
+	CgroupMode   namespaces.CgroupMode //cgroup
+}
+
+// UserConfig configures the user namespace for the container
+type UserConfig struct {
+	GroupAdd   []string // group-add
+	IDMappings *storage.IDMappingOptions
+	UsernsMode namespaces.UsernsMode //userns
+	User       string                //user
+}
+
+// UtsConfig configures the uts namespace for the container
+type UtsConfig struct {
+	UtsMode  namespaces.UTSMode //uts
+	NoHosts  bool
+	HostAdd  []string //add-host
+	Hostname string
+}
+
+// NetworkConfig configures the network namespace for the container
+type NetworkConfig struct {
+	DNSOpt       []string //dns-opt
+	DNSSearch    []string //dns-search
+	DNSServers   []string //dns
+	ExposedPorts map[nat.Port]struct{}
+	HTTPProxy    bool
+	IP6Address   string                 //ipv6
+	IPAddress    string                 //ip
+	LinkLocalIP  []string               // link-local-ip
+	MacAddress   string                 //mac-address
+	NetMode      namespaces.NetworkMode //net
+	Network      string                 //network
+	NetworkAlias []string               //network-alias
+	PortBindings nat.PortMap
+	Publish      []string //publish
+	PublishAll   bool     //publish-all
+}
+
+// SecurityConfig configures the security features for the container
+type SecurityConfig struct {
 	CapAdd             []string // cap-add
 	CapDrop            []string // cap-drop
-	CidFile            string
-	ConmonPidFile      string
-	Cgroupns           string
-	Cgroups            string
-	CgroupParent       string            // cgroup-parent
-	Command            []string          // Full command that will be used
-	UserCommand        []string          // User-entered command (or image CMD)
-	Detach             bool              // detach
-	Devices            []string          // device
-	DNSOpt             []string          //dns-opt
-	DNSSearch          []string          //dns-search
-	DNSServers         []string          //dns
-	Entrypoint         []string          //entrypoint
-	Env                map[string]string //env
-	ExposedPorts       map[nat.Port]struct{}
-	GroupAdd           []string // group-add
-	HealthCheck        *manifest.Schema2HealthConfig
-	NoHosts            bool
-	HostAdd            []string //add-host
-	Hostname           string   //hostname
-	HTTPProxy          bool
-	Init               bool   // init
-	InitPath           string //init-path
-	Image              string
-	ImageID            string
-	BuiltinImgVolumes  map[string]struct{} // volumes defined in the image config
-	IDMappings         *storage.IDMappingOptions
-	ImageVolumeType    string                 // how to handle the image volume, either bind, tmpfs, or ignore
-	Interactive        bool                   //interactive
-	IpcMode            namespaces.IpcMode     //ipc
-	IP6Address         string                 //ipv6
-	IPAddress          string                 //ip
-	Labels             map[string]string      //label
-	LinkLocalIP        []string               // link-local-ip
-	LogDriver          string                 // log-driver
-	LogDriverOpt       []string               // log-opt
-	MacAddress         string                 //mac-address
-	Name               string                 //name
-	NetMode            namespaces.NetworkMode //net
-	Network            string                 //network
-	NetworkAlias       []string               //network-alias
-	PidMode            namespaces.PidMode     //pid
-	Pod                string                 //pod
-	PodmanPath         string
-	CgroupMode         namespaces.CgroupMode //cgroup
-	PortBindings       nat.PortMap
-	Privileged         bool     //privileged
-	Publish            []string //publish
-	PublishAll         bool     //publish-all
-	Quiet              bool     //quiet
-	ReadOnlyRootfs     bool     //read-only
-	ReadOnlyTmpfs      bool     //read-only-tmpfs
-	Resources          CreateResourceConfig
-	RestartPolicy      string
-	Rm                 bool              //rm
-	StopSignal         syscall.Signal    // stop-signal
-	StopTimeout        uint              // stop-timeout
-	Sysctl             map[string]string //sysctl
-	Systemd            bool
-	Tmpfs              []string              // tmpfs
-	Tty                bool                  //tty
-	UsernsMode         namespaces.UsernsMode //userns
-	User               string                //user
-	UtsMode            namespaces.UTSMode    //uts
-	Mounts             []spec.Mount
-	MountsFlag         []string // mounts
-	NamedVolumes       []*libpod.ContainerNamedVolume
-	Volumes            []string //volume
-	VolumesFrom        []string
-	WorkDir            string   //workdir
 	LabelOpts          []string //SecurityOpts
 	NoNewPrivs         bool     //SecurityOpts
 	ApparmorProfile    string   //SecurityOpts
 	SeccompProfilePath string   //SecurityOpts
 	SecurityOpts       []string
-	Rootfs             string
-	Syslog             bool // Whether to enable syslog on exit commands
+	Privileged         bool              //privileged
+	ReadOnlyRootfs     bool              //read-only
+	ReadOnlyTmpfs      bool              //read-only-tmpfs
+	Sysctl             map[string]string //sysctl
+}
+
+// CreateConfig is a pre OCI spec structure.  It represents user input from varlink or the CLI
+type CreateConfig struct {
+	Annotations       map[string]string
+	Args              []string
+	CidFile           string
+	ConmonPidFile     string
+	Command           []string          // Full command that will be used
+	UserCommand       []string          // User-entered command (or image CMD)
+	Detach            bool              // detach
+	Devices           []string          // device
+	Entrypoint        []string          //entrypoint
+	Env               map[string]string //env
+	HealthCheck       *manifest.Schema2HealthConfig
+	Init              bool   // init
+	InitPath          string //init-path
+	Image             string
+	ImageID           string
+	BuiltinImgVolumes map[string]struct{} // volumes defined in the image config
+	ImageVolumeType   string              // how to handle the image volume, either bind, tmpfs, or ignore
+	Interactive       bool                //interactive
+	Labels            map[string]string   //label
+	LogDriver         string              // log-driver
+	LogDriverOpt      []string            // log-opt
+	Name              string              //name
+	PodmanPath        string
+	Pod               string //pod
+	Quiet             bool   //quiet
+	Resources         CreateResourceConfig
+	RestartPolicy     string
+	Rm                bool           //rm
+	StopSignal        syscall.Signal // stop-signal
+	StopTimeout       uint           // stop-timeout
+	Systemd           bool
+	Tmpfs             []string // tmpfs
+	Tty               bool     //tty
+	Mounts            []spec.Mount
+	MountsFlag        []string // mounts
+	NamedVolumes      []*libpod.ContainerNamedVolume
+	Volumes           []string //volume
+	VolumesFrom       []string
+	WorkDir           string //workdir
+	Rootfs            string
+	Security          SecurityConfig
+	Syslog            bool // Whether to enable syslog on exit commands
+
+	// Namespaces
+	Pid     PidConfig
+	Ipc     IpcConfig
+	Cgroup  CgroupConfig
+	User    UserConfig
+	Uts     UtsConfig
+	Network NetworkConfig
 }
 
 func u32Ptr(i int64) *uint32     { u := uint32(i); return &u }
@@ -199,7 +234,6 @@ func (c *CreateConfig) createExitCommand(runtime *libpod.Runtime) ([]string, err
 // GetContainerCreateOptions takes a CreateConfig and returns a slice of CtrCreateOptions
 func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *libpod.Pod, mounts []spec.Mount, namedVolumes []*libpod.ContainerNamedVolume) ([]libpod.CtrCreateOption, error) {
 	var options []libpod.CtrCreateOption
-	var portBindings []ocicni.PortMapping
 	var err error
 
 	if c.Interactive {
@@ -216,15 +250,6 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l
 		logrus.Debugf("adding container to pod %s", c.Pod)
 		options = append(options, runtime.WithPod(pod))
 	}
-	if c.Cgroups == "disabled" {
-		options = append(options, libpod.WithNoCgroups())
-	}
-	if len(c.PortBindings) > 0 {
-		portBindings, err = c.CreatePortBindings()
-		if err != nil {
-			return nil, errors.Wrapf(err, "unable to create port bindings")
-		}
-	}
 
 	if len(mounts) != 0 || len(namedVolumes) != 0 {
 		destinations := []string{}
@@ -253,187 +278,72 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l
 	// does not have one
 	options = append(options, libpod.WithEntrypoint(c.Entrypoint))
 
-	networks := make([]string, 0)
-	userNetworks := c.NetMode.UserDefined()
-	if IsPod(userNetworks) {
-		userNetworks = ""
-	}
-	if userNetworks != "" {
-		for _, netName := range strings.Split(userNetworks, ",") {
-			if netName == "" {
-				return nil, errors.Wrapf(err, "container networks %q invalid", networks)
-			}
-			networks = append(networks, netName)
-		}
-	}
-
-	if c.NetMode.IsNS() {
-		ns := c.NetMode.NS()
-		if ns == "" {
-			return nil, errors.Errorf("invalid empty user-defined network namespace")
-		}
-		_, err := os.Stat(ns)
-		if err != nil {
-			return nil, err
-		}
-	} else if c.NetMode.IsContainer() {
-		connectedCtr, err := runtime.LookupContainer(c.NetMode.Container())
-		if err != nil {
-			return nil, errors.Wrapf(err, "container %q not found", c.NetMode.Container())
-		}
-		options = append(options, libpod.WithNetNSFrom(connectedCtr))
-	} else if !c.NetMode.IsHost() && !c.NetMode.IsNone() {
-		hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0
-		postConfigureNetNS := hasUserns && !c.UsernsMode.IsHost()
-		options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS, string(c.NetMode), networks))
-	}
-
-	if c.CgroupMode.IsNS() {
-		ns := c.CgroupMode.NS()
-		if ns == "" {
-			return nil, errors.Errorf("invalid empty user-defined network namespace")
-		}
-		_, err := os.Stat(ns)
-		if err != nil {
-			return nil, err
-		}
-	} else if c.CgroupMode.IsContainer() {
-		connectedCtr, err := runtime.LookupContainer(c.CgroupMode.Container())
-		if err != nil {
-			return nil, errors.Wrapf(err, "container %q not found", c.CgroupMode.Container())
-		}
-		options = append(options, libpod.WithCgroupNSFrom(connectedCtr))
-	}
+	// TODO: MNT, USER, CGROUP
+	options = append(options, libpod.WithStopSignal(c.StopSignal))
+	options = append(options, libpod.WithStopTimeout(c.StopTimeout))
 
-	if c.UsernsMode.IsNS() {
-		ns := c.UsernsMode.NS()
-		if ns == "" {
-			return nil, errors.Errorf("invalid empty user-defined user namespace")
-		}
-		_, err := os.Stat(ns)
-		if err != nil {
-			return nil, err
-		}
-		options = append(options, libpod.WithIDMappings(*c.IDMappings))
-	} else if c.UsernsMode.IsContainer() {
-		connectedCtr, err := runtime.LookupContainer(c.UsernsMode.Container())
-		if err != nil {
-			return nil, errors.Wrapf(err, "container %q not found", c.UsernsMode.Container())
-		}
-		options = append(options, libpod.WithUserNSFrom(connectedCtr))
-	} else {
-		options = append(options, libpod.WithIDMappings(*c.IDMappings))
+	logPath := getLoggingPath(c.LogDriverOpt)
+	if logPath != "" {
+		options = append(options, libpod.WithLogPath(logPath))
 	}
 
-	if c.PidMode.IsContainer() {
-		connectedCtr, err := runtime.LookupContainer(c.PidMode.Container())
-		if err != nil {
-			return nil, errors.Wrapf(err, "container %q not found", c.PidMode.Container())
-		}
-
-		options = append(options, libpod.WithPIDNSFrom(connectedCtr))
+	if c.LogDriver != "" {
+		options = append(options, libpod.WithLogDriver(c.LogDriver))
 	}
 
-	if c.IpcMode.IsContainer() {
-		connectedCtr, err := runtime.LookupContainer(c.IpcMode.Container())
-		if err != nil {
-			return nil, errors.Wrapf(err, "container %q not found", c.IpcMode.Container())
-		}
-
-		options = append(options, libpod.WithIPCNSFrom(connectedCtr))
+	secOpts, err := c.Security.ToCreateOptions()
+	if err != nil {
+		return nil, err
 	}
+	options = append(options, secOpts...)
 
-	if IsPod(string(c.UtsMode)) {
-		options = append(options, libpod.WithUTSNSFromPod(pod))
+	nsOpts, err := c.Cgroup.ToCreateOptions(runtime)
+	if err != nil {
+		return nil, err
 	}
-	if c.UtsMode.IsContainer() {
-		connectedCtr, err := runtime.LookupContainer(c.UtsMode.Container())
-		if err != nil {
-			return nil, errors.Wrapf(err, "container %q not found", c.UtsMode.Container())
-		}
+	options = append(options, nsOpts...)
 
-		options = append(options, libpod.WithUTSNSFrom(connectedCtr))
+	nsOpts, err = c.Ipc.ToCreateOptions(runtime)
+	if err != nil {
+		return nil, err
 	}
+	options = append(options, nsOpts...)
 
-	// TODO: MNT, USER, CGROUP
-	options = append(options, libpod.WithStopSignal(c.StopSignal))
-	options = append(options, libpod.WithStopTimeout(c.StopTimeout))
-	if len(c.DNSSearch) > 0 {
-		options = append(options, libpod.WithDNSSearch(c.DNSSearch))
-	}
-	if len(c.DNSServers) > 0 {
-		if len(c.DNSServers) == 1 && strings.ToLower(c.DNSServers[0]) == "none" {
-			options = append(options, libpod.WithUseImageResolvConf())
-		} else {
-			options = append(options, libpod.WithDNS(c.DNSServers))
-		}
-	}
-	if len(c.DNSOpt) > 0 {
-		options = append(options, libpod.WithDNSOption(c.DNSOpt))
-	}
-	if c.NoHosts {
-		options = append(options, libpod.WithUseImageHosts())
-	}
-	if len(c.HostAdd) > 0 && !c.NoHosts {
-		options = append(options, libpod.WithHosts(c.HostAdd))
-	}
-	logPath := getLoggingPath(c.LogDriverOpt)
-	if logPath != "" {
-		options = append(options, libpod.WithLogPath(logPath))
+	nsOpts, err = c.Pid.ToCreateOptions(runtime)
+	if err != nil {
+		return nil, err
 	}
+	options = append(options, nsOpts...)
 
-	if c.LogDriver != "" {
-		options = append(options, libpod.WithLogDriver(c.LogDriver))
+	nsOpts, err = c.Network.ToCreateOptions(runtime, &c.User)
+	if err != nil {
+		return nil, err
 	}
+	options = append(options, nsOpts...)
 
-	if c.IPAddress != "" {
-		ip := net.ParseIP(c.IPAddress)
-		if ip == nil {
-			return nil, errors.Wrapf(define.ErrInvalidArg, "cannot parse %s as IP address", c.IPAddress)
-		} else if ip.To4() == nil {
-			return nil, errors.Wrapf(define.ErrInvalidArg, "%s is not an IPv4 address", c.IPAddress)
-		}
-		options = append(options, libpod.WithStaticIP(ip))
+	nsOpts, err = c.Uts.ToCreateOptions(runtime, pod)
+	if err != nil {
+		return nil, err
 	}
+	options = append(options, nsOpts...)
 
-	if c.MacAddress != "" {
-		mac, err := net.ParseMAC(c.MacAddress)
-		if err != nil {
-			return nil, errors.Wrapf(define.ErrInvalidArg, "cannot parse %s as MAC address: %v", c.MacAddress, err)
-		}
-		options = append(options, libpod.WithStaticMAC(mac))
+	nsOpts, err = c.User.ToCreateOptions(runtime)
+	if err != nil {
+		return nil, err
 	}
-
-	options = append(options, libpod.WithPrivileged(c.Privileged))
+	options = append(options, nsOpts...)
 
 	useImageVolumes := c.ImageVolumeType == TypeBind
 	// Gather up the options for NewContainer which consist of With... funcs
 	options = append(options, libpod.WithRootFSFromImage(c.ImageID, c.Image, useImageVolumes))
-	options = append(options, libpod.WithSecLabels(c.LabelOpts))
 	options = append(options, libpod.WithConmonPidFile(c.ConmonPidFile))
 	options = append(options, libpod.WithLabels(c.Labels))
-	options = append(options, libpod.WithUser(c.User))
-	if c.IpcMode.IsHost() {
-		options = append(options, libpod.WithShmDir("/dev/shm"))
-
-	} else if c.IpcMode.IsContainer() {
-		ctr, err := runtime.LookupContainer(c.IpcMode.Container())
-		if err != nil {
-			return nil, errors.Wrapf(err, "container %q not found", c.IpcMode.Container())
-		}
-		options = append(options, libpod.WithShmDir(ctr.ShmDir()))
-	}
 	options = append(options, libpod.WithShmSize(c.Resources.ShmSize))
-	options = append(options, libpod.WithGroups(c.GroupAdd))
 	if c.Rootfs != "" {
 		options = append(options, libpod.WithRootFS(c.Rootfs))
 	}
 	// Default used if not overridden on command line
 
-	if c.CgroupParent != "" {
-		options = append(options, libpod.WithCgroupParent(c.CgroupParent))
-	}
-
 	if c.RestartPolicy != "" {
 		if c.RestartPolicy == "unless-stopped" {
 			return nil, errors.Wrapf(define.ErrInvalidArg, "the unless-stopped restart policy is not supported")
@@ -467,38 +377,6 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l
 	return options, nil
 }
 
-// CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands
-func (c *CreateConfig) CreatePortBindings() ([]ocicni.PortMapping, error) {
-	return NatToOCIPortBindings(c.PortBindings)
-}
-
-// NatToOCIPortBindings iterates a nat.portmap slice and creates []ocicni portmapping slice
-func NatToOCIPortBindings(ports nat.PortMap) ([]ocicni.PortMapping, error) {
-	var portBindings []ocicni.PortMapping
-	for containerPb, hostPb := range ports {
-		var pm ocicni.PortMapping
-		pm.ContainerPort = int32(containerPb.Int())
-		for _, i := range hostPb {
-			var hostPort int
-			var err error
-			pm.HostIP = i.HostIP
-			if i.HostPort == "" {
-				hostPort = containerPb.Int()
-			} else {
-				hostPort, err = strconv.Atoi(i.HostPort)
-				if err != nil {
-					return nil, errors.Wrapf(err, "unable to convert host port to integer")
-				}
-			}
-
-			pm.HostPort = int32(hostPort)
-			pm.Protocol = containerPb.Proto()
-			portBindings = append(portBindings, pm)
-		}
-	}
-	return portBindings, nil
-}
-
 // AddPrivilegedDevices iterates through host devices and adds all
 // host devices to the spec
 func (c *CreateConfig) AddPrivilegedDevices(g *generate.Generator) error {
diff --git a/pkg/spec/namespaces.go b/pkg/spec/namespaces.go
new file mode 100644
index 0000000000..a451374164
--- /dev/null
+++ b/pkg/spec/namespaces.go
@@ -0,0 +1,433 @@
+package createconfig
+
+import (
+	"net"
+	"os"
+	"strconv"
+	"strings"
+
+	"github.com/containers/libpod/libpod"
+	"github.com/containers/libpod/libpod/define"
+	"github.com/containers/libpod/pkg/cgroups"
+	"github.com/cri-o/ocicni/pkg/ocicni"
+	"github.com/docker/go-connections/nat"
+	spec "github.com/opencontainers/runtime-spec/specs-go"
+	"github.com/opencontainers/runtime-tools/generate"
+	"github.com/pkg/errors"
+	"github.com/sirupsen/logrus"
+)
+
+func (c *NetworkConfig) ToCreateOptions(runtime *libpod.Runtime, userns *UserConfig) ([]libpod.CtrCreateOption, error) {
+	var portBindings []ocicni.PortMapping
+	var err error
+	if len(c.PortBindings) > 0 {
+		portBindings, err = NatToOCIPortBindings(c.PortBindings)
+		if err != nil {
+			return nil, errors.Wrapf(err, "unable to create port bindings")
+		}
+	}
+
+	options := make([]libpod.CtrCreateOption, 0)
+	userNetworks := c.NetMode.UserDefined()
+	networks := make([]string, 0)
+
+	if IsPod(userNetworks) {
+		userNetworks = ""
+	}
+	if userNetworks != "" {
+		for _, netName := range strings.Split(userNetworks, ",") {
+			if netName == "" {
+				return nil, errors.Errorf("container networks %q invalid", userNetworks)
+			}
+			networks = append(networks, netName)
+		}
+	}
+
+	if c.NetMode.IsNS() {
+		ns := c.NetMode.NS()
+		if ns == "" {
+			return nil, errors.Errorf("invalid empty user-defined network namespace")
+		}
+		_, err := os.Stat(ns)
+		if err != nil {
+			return nil, err
+		}
+	} else if c.NetMode.IsContainer() {
+		connectedCtr, err := runtime.LookupContainer(c.NetMode.Container())
+		if err != nil {
+			return nil, errors.Wrapf(err, "container %q not found", c.NetMode.Container())
+		}
+		options = append(options, libpod.WithNetNSFrom(connectedCtr))
+	} else if !c.NetMode.IsHost() && !c.NetMode.IsNone() {
+		postConfigureNetNS := userns.getPostConfigureNetNS()
+		options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS, string(c.NetMode), networks))
+	}
+
+	if len(c.DNSSearch) > 0 {
+		options = append(options, libpod.WithDNSSearch(c.DNSSearch))
+	}
+	if len(c.DNSServers) > 0 {
+		if len(c.DNSServers) == 1 && strings.ToLower(c.DNSServers[0]) == "none" {
+			options = append(options, libpod.WithUseImageResolvConf())
+		} else {
+			options = append(options, libpod.WithDNS(c.DNSServers))
+		}
+	}
+	if len(c.DNSOpt) > 0 {
+		options = append(options, libpod.WithDNSOption(c.DNSOpt))
+	}
+	if c.IPAddress != "" {
+		ip := net.ParseIP(c.IPAddress)
+		if ip == nil {
+			return nil, errors.Wrapf(define.ErrInvalidArg, "cannot parse %s as IP address", c.IPAddress)
+		} else if ip.To4() == nil {
+			return nil, errors.Wrapf(define.ErrInvalidArg, "%s is not an IPv4 address", c.IPAddress)
+		}
+		options = append(options, libpod.WithStaticIP(ip))
+	}
+
+	if c.MacAddress != "" {
+		mac, err := net.ParseMAC(c.MacAddress)
+		if err != nil {
+			return nil, errors.Wrapf(define.ErrInvalidArg, "cannot parse %s as MAC address: %v", c.MacAddress, err)
+		}
+		options = append(options, libpod.WithStaticMAC(mac))
+	}
+
+	return options, nil
+}
+
+func (c *NetworkConfig) ConfigureGenerator(g *generate.Generator) error {
+	netMode := c.NetMode
+	if netMode.IsHost() {
+		logrus.Debug("Using host netmode")
+		if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
+			return err
+		}
+	} else if netMode.IsNone() {
+		logrus.Debug("Using none netmode")
+	} else if netMode.IsBridge() {
+		logrus.Debug("Using bridge netmode")
+	} else if netCtr := netMode.Container(); netCtr != "" {
+		logrus.Debugf("using container %s netmode", netCtr)
+	} else if IsNS(string(netMode)) {
+		logrus.Debug("Using ns netmode")
+		if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), NS(string(netMode))); err != nil {
+			return err
+		}
+	} else if IsPod(string(netMode)) {
+		logrus.Debug("Using pod netmode, unless pod is not sharing")
+	} else if netMode.IsSlirp4netns() {
+		logrus.Debug("Using slirp4netns netmode")
+	} else if netMode.IsUserDefined() {
+		logrus.Debug("Using user defined netmode")
+	} else {
+		return errors.Errorf("unknown network mode")
+	}
+
+	if c.HTTPProxy {
+		for _, envSpec := range []string{
+			"http_proxy",
+			"HTTP_PROXY",
+			"https_proxy",
+			"HTTPS_PROXY",
+			"ftp_proxy",
+			"FTP_PROXY",
+			"no_proxy",
+			"NO_PROXY",
+		} {
+			envVal := os.Getenv(envSpec)
+			if envVal != "" {
+				g.AddProcessEnv(envSpec, envVal)
+			}
+		}
+	}
+
+	if g.Config.Annotations == nil {
+		g.Config.Annotations = make(map[string]string)
+	}
+
+	if c.PublishAll {
+		g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseTrue
+	} else {
+		g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseFalse
+	}
+
+	return nil
+}
+
+// NatToOCIPortBindings iterates a nat.portmap slice and creates []ocicni portmapping slice
+func NatToOCIPortBindings(ports nat.PortMap) ([]ocicni.PortMapping, error) {
+	var portBindings []ocicni.PortMapping
+	for containerPb, hostPb := range ports {
+		var pm ocicni.PortMapping
+		pm.ContainerPort = int32(containerPb.Int())
+		for _, i := range hostPb {
+			var hostPort int
+			var err error
+			pm.HostIP = i.HostIP
+			if i.HostPort == "" {
+				hostPort = containerPb.Int()
+			} else {
+				hostPort, err = strconv.Atoi(i.HostPort)
+				if err != nil {
+					return nil, errors.Wrapf(err, "unable to convert host port to integer")
+				}
+			}
+
+			pm.HostPort = int32(hostPort)
+			pm.Protocol = containerPb.Proto()
+			portBindings = append(portBindings, pm)
+		}
+	}
+	return portBindings, nil
+}
+
+func (c *CgroupConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
+	options := make([]libpod.CtrCreateOption, 0)
+	if c.CgroupMode.IsNS() {
+		ns := c.CgroupMode.NS()
+		if ns == "" {
+			return nil, errors.Errorf("invalid empty user-defined network namespace")
+		}
+		_, err := os.Stat(ns)
+		if err != nil {
+			return nil, err
+		}
+	} else if c.CgroupMode.IsContainer() {
+		connectedCtr, err := runtime.LookupContainer(c.CgroupMode.Container())
+		if err != nil {
+			return nil, errors.Wrapf(err, "container %q not found", c.CgroupMode.Container())
+		}
+		options = append(options, libpod.WithCgroupNSFrom(connectedCtr))
+	}
+
+	if c.CgroupParent != "" {
+		options = append(options, libpod.WithCgroupParent(c.CgroupParent))
+	}
+
+	if c.Cgroups == "disabled" {
+		options = append(options, libpod.WithNoCgroups())
+	}
+
+	return options, nil
+}
+
+func (c *UserConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
+	options := make([]libpod.CtrCreateOption, 0)
+	if c.UsernsMode.IsNS() {
+		ns := c.UsernsMode.NS()
+		if ns == "" {
+			return nil, errors.Errorf("invalid empty user-defined user namespace")
+		}
+		_, err := os.Stat(ns)
+		if err != nil {
+			return nil, err
+		}
+		options = append(options, libpod.WithIDMappings(*c.IDMappings))
+	} else if c.UsernsMode.IsContainer() {
+		connectedCtr, err := runtime.LookupContainer(c.UsernsMode.Container())
+		if err != nil {
+			return nil, errors.Wrapf(err, "container %q not found", c.UsernsMode.Container())
+		}
+		options = append(options, libpod.WithUserNSFrom(connectedCtr))
+	} else {
+		options = append(options, libpod.WithIDMappings(*c.IDMappings))
+	}
+
+	options = append(options, libpod.WithUser(c.User))
+	options = append(options, libpod.WithGroups(c.GroupAdd))
+
+	return options, nil
+}
+
+func (c *UserConfig) ConfigureGenerator(g *generate.Generator) error {
+	if IsNS(string(c.UsernsMode)) {
+		if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), NS(string(c.UsernsMode))); err != nil {
+			return err
+		}
+		// runc complains if no mapping is specified, even if we join another ns.  So provide a dummy mapping
+		g.AddLinuxUIDMapping(uint32(0), uint32(0), uint32(1))
+		g.AddLinuxGIDMapping(uint32(0), uint32(0), uint32(1))
+	}
+
+	if (len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0) && !c.UsernsMode.IsHost() {
+		if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil {
+			return err
+		}
+	}
+	for _, uidmap := range c.IDMappings.UIDMap {
+		g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size))
+	}
+	for _, gidmap := range c.IDMappings.GIDMap {
+		g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size))
+	}
+	return nil
+}
+
+func (c *UserConfig) getPostConfigureNetNS() bool {
+	hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0
+	postConfigureNetNS := hasUserns && !c.UsernsMode.IsHost()
+	return postConfigureNetNS
+}
+
+func (c *UserConfig) InNS(isRootless bool) bool {
+	hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0
+	return isRootless || (hasUserns && !c.UsernsMode.IsHost())
+}
+
+func (c *IpcConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
+	options := make([]libpod.CtrCreateOption, 0)
+	if c.IpcMode.IsHost() {
+		options = append(options, libpod.WithShmDir("/dev/shm"))
+	} else if c.IpcMode.IsContainer() {
+		connectedCtr, err := runtime.LookupContainer(c.IpcMode.Container())
+		if err != nil {
+			return nil, errors.Wrapf(err, "container %q not found", c.IpcMode.Container())
+		}
+
+		options = append(options, libpod.WithIPCNSFrom(connectedCtr))
+		options = append(options, libpod.WithShmDir(connectedCtr.ShmDir()))
+	}
+
+	return options, nil
+}
+
+func (c *IpcConfig) ConfigureGenerator(g *generate.Generator) error {
+	ipcMode := c.IpcMode
+	if IsNS(string(ipcMode)) {
+		return g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), NS(string(ipcMode)))
+	}
+	if ipcMode.IsHost() {
+		return g.RemoveLinuxNamespace(string(spec.IPCNamespace))
+	}
+	if ipcCtr := ipcMode.Container(); ipcCtr != "" {
+		logrus.Debugf("Using container %s ipcmode", ipcCtr)
+	}
+
+	return nil
+}
+
+func (c *CgroupConfig) ConfigureGenerator(g *generate.Generator) error {
+	cgroupMode := c.CgroupMode
+	if cgroupMode.IsDefaultValue() {
+		// If the value is not specified, default to "private" on cgroups v2 and "host" on cgroups v1.
+		unified, err := cgroups.IsCgroup2UnifiedMode()
+		if err != nil {
+			return err
+		}
+		if unified {
+			cgroupMode = "private"
+		} else {
+			cgroupMode = "host"
+		}
+	}
+	if cgroupMode.IsNS() {
+		return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), NS(string(cgroupMode)))
+	}
+	if cgroupMode.IsHost() {
+		return g.RemoveLinuxNamespace(string(spec.CgroupNamespace))
+	}
+	if cgroupMode.IsPrivate() {
+		return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), "")
+	}
+	if cgCtr := cgroupMode.Container(); cgCtr != "" {
+		logrus.Debugf("Using container %s cgroup mode", cgCtr)
+	}
+	return nil
+}
+
+func (c *PidConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
+	options := make([]libpod.CtrCreateOption, 0)
+	if c.PidMode.IsContainer() {
+		connectedCtr, err := runtime.LookupContainer(c.PidMode.Container())
+		if err != nil {
+			return nil, errors.Wrapf(err, "container %q not found", c.PidMode.Container())
+		}
+
+		options = append(options, libpod.WithPIDNSFrom(connectedCtr))
+	}
+
+	return options, nil
+}
+
+func (c *PidConfig) ConfigureGenerator(g *generate.Generator) error {
+	pidMode := c.PidMode
+	if IsNS(string(pidMode)) {
+		return g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), NS(string(pidMode)))
+	}
+	if pidMode.IsHost() {
+		return g.RemoveLinuxNamespace(string(spec.PIDNamespace))
+	}
+	if pidCtr := pidMode.Container(); pidCtr != "" {
+		logrus.Debugf("using container %s pidmode", pidCtr)
+	}
+	if IsPod(string(pidMode)) {
+		logrus.Debug("using pod pidmode")
+	}
+	return nil
+}
+
+func (c *UtsConfig) ToCreateOptions(runtime *libpod.Runtime, pod *libpod.Pod) ([]libpod.CtrCreateOption, error) {
+	options := make([]libpod.CtrCreateOption, 0)
+	if IsPod(string(c.UtsMode)) {
+		options = append(options, libpod.WithUTSNSFromPod(pod))
+	}
+	if c.UtsMode.IsContainer() {
+		connectedCtr, err := runtime.LookupContainer(c.UtsMode.Container())
+		if err != nil {
+			return nil, errors.Wrapf(err, "container %q not found", c.UtsMode.Container())
+		}
+
+		options = append(options, libpod.WithUTSNSFrom(connectedCtr))
+	}
+	if c.NoHosts {
+		options = append(options, libpod.WithUseImageHosts())
+	}
+	if len(c.HostAdd) > 0 && !c.NoHosts {
+		options = append(options, libpod.WithHosts(c.HostAdd))
+	}
+
+	return options, nil
+}
+
+func (c *UtsConfig) ConfigureGenerator(g *generate.Generator, net *NetworkConfig, runtime *libpod.Runtime) error {
+	hostname := c.Hostname
+	var err error
+	if hostname == "" {
+		if utsCtrID := c.UtsMode.Container(); utsCtrID != "" {
+			utsCtr, err := runtime.GetContainer(utsCtrID)
+			if err != nil {
+				return errors.Wrapf(err, "unable to retrieve hostname from dependency container %s", utsCtrID)
+			}
+			hostname = utsCtr.Hostname()
+		} else if net.NetMode.IsHost() || c.UtsMode.IsHost() {
+			hostname, err = os.Hostname()
+			if err != nil {
+				return errors.Wrap(err, "unable to retrieve hostname of the host")
+			}
+		} else {
+			logrus.Debug("No hostname set; container's hostname will default to runtime default")
+		}
+	}
+	g.RemoveHostname()
+	if c.Hostname != "" || !c.UtsMode.IsHost() {
+		// Set the hostname in the OCI configuration only
+		// if specified by the user or if we are creating
+		// a new UTS namespace.
+		g.SetHostname(hostname)
+	}
+	g.AddProcessEnv("HOSTNAME", hostname)
+
+	utsMode := c.UtsMode
+	if IsNS(string(utsMode)) {
+		return g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), NS(string(utsMode)))
+	}
+	if utsMode.IsHost() {
+		return g.RemoveLinuxNamespace(string(spec.UTSNamespace))
+	}
+	if utsCtr := utsMode.Container(); utsCtr != "" {
+		logrus.Debugf("using container %s utsmode", utsCtr)
+	}
+	return nil
+}
diff --git a/pkg/spec/security.go b/pkg/spec/security.go
new file mode 100644
index 0000000000..05ed94e665
--- /dev/null
+++ b/pkg/spec/security.go
@@ -0,0 +1,172 @@
+package createconfig
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/containers/libpod/libpod"
+	"github.com/docker/docker/oci/caps"
+	"github.com/opencontainers/runtime-tools/generate"
+	"github.com/opencontainers/selinux/go-selinux/label"
+	"github.com/pkg/errors"
+)
+
+func (c *SecurityConfig) ToCreateOptions() ([]libpod.CtrCreateOption, error) {
+	options := make([]libpod.CtrCreateOption, 0)
+	options = append(options, libpod.WithSecLabels(c.LabelOpts))
+	options = append(options, libpod.WithPrivileged(c.Privileged))
+	return options, nil
+}
+
+func (c *SecurityConfig) SetLabelOpts(runtime *libpod.Runtime, pidConfig *PidConfig, ipcConfig *IpcConfig) error {
+	if c.Privileged {
+		c.LabelOpts = label.DisableSecOpt()
+		return nil
+	}
+
+	var labelOpts []string
+	if pidConfig.PidMode.IsHost() {
+		labelOpts = append(labelOpts, label.DisableSecOpt()...)
+	} else if pidConfig.PidMode.IsContainer() {
+		ctr, err := runtime.LookupContainer(pidConfig.PidMode.Container())
+		if err != nil {
+			return errors.Wrapf(err, "container %q not found", pidConfig.PidMode.Container())
+		}
+		secopts, err := label.DupSecOpt(ctr.ProcessLabel())
+		if err != nil {
+			return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
+		}
+		labelOpts = append(labelOpts, secopts...)
+	}
+
+	if ipcConfig.IpcMode.IsHost() {
+		labelOpts = append(labelOpts, label.DisableSecOpt()...)
+	} else if ipcConfig.IpcMode.IsContainer() {
+		ctr, err := runtime.LookupContainer(ipcConfig.IpcMode.Container())
+		if err != nil {
+			return errors.Wrapf(err, "container %q not found", ipcConfig.IpcMode.Container())
+		}
+		secopts, err := label.DupSecOpt(ctr.ProcessLabel())
+		if err != nil {
+			return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
+		}
+		labelOpts = append(labelOpts, secopts...)
+	}
+
+	c.LabelOpts = append(c.LabelOpts, labelOpts...)
+	return nil
+}
+
+func (c *SecurityConfig) SetSecurityOpts(runtime *libpod.Runtime, securityOpts []string) error {
+	for _, opt := range securityOpts {
+		if opt == "no-new-privileges" {
+			c.NoNewPrivs = true
+		} else {
+			con := strings.SplitN(opt, "=", 2)
+			if len(con) != 2 {
+				return fmt.Errorf("invalid --security-opt 1: %q", opt)
+			}
+
+			switch con[0] {
+			case "label":
+				c.LabelOpts = append(c.LabelOpts, con[1])
+			case "apparmor":
+				c.ApparmorProfile = con[1]
+			case "seccomp":
+				c.SeccompProfilePath = con[1]
+			default:
+				return fmt.Errorf("invalid --security-opt 2: %q", opt)
+			}
+		}
+	}
+
+	if c.SeccompProfilePath == "" {
+		var err error
+		c.SeccompProfilePath, err = libpod.DefaultSeccompPath()
+		if err != nil {
+			return err
+		}
+	}
+	c.SecurityOpts = securityOpts
+	return nil
+}
+
+func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserConfig) error {
+	// HANDLE CAPABILITIES
+	// NOTE: Must happen before SECCOMP
+	if c.Privileged {
+		g.SetupPrivileged(true)
+	}
+
+	useNotRoot := func(user string) bool {
+		if user == "" || user == "root" || user == "0" {
+			return false
+		}
+		return true
+	}
+
+	configSpec := g.Config
+	var err error
+	var caplist []string
+	bounding := configSpec.Process.Capabilities.Bounding
+	if useNotRoot(user.User) {
+		configSpec.Process.Capabilities.Bounding = caplist
+	}
+	caplist, err = caps.TweakCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.CapDrop, nil, false)
+	if err != nil {
+		return err
+	}
+
+	configSpec.Process.Capabilities.Bounding = caplist
+	configSpec.Process.Capabilities.Permitted = caplist
+	configSpec.Process.Capabilities.Inheritable = caplist
+	configSpec.Process.Capabilities.Effective = caplist
+	configSpec.Process.Capabilities.Ambient = caplist
+	if useNotRoot(user.User) {
+		caplist, err = caps.TweakCapabilities(bounding, c.CapAdd, c.CapDrop, nil, false)
+		if err != nil {
+			return err
+		}
+	}
+	configSpec.Process.Capabilities.Bounding = caplist
+
+	// HANDLE SECCOMP
+	if c.SeccompProfilePath != "unconfined" {
+		seccompConfig, err := getSeccompConfig(c, configSpec)
+		if err != nil {
+			return err
+		}
+		configSpec.Linux.Seccomp = seccompConfig
+	}
+
+	// Clear default Seccomp profile from Generator for privileged containers
+	if c.SeccompProfilePath == "unconfined" || c.Privileged {
+		configSpec.Linux.Seccomp = nil
+	}
+
+	for _, opt := range c.SecurityOpts {
+		// Split on both : and =
+		splitOpt := strings.Split(opt, "=")
+		if len(splitOpt) == 1 {
+			splitOpt = strings.Split(opt, ":")
+		}
+		if len(splitOpt) < 2 {
+			continue
+		}
+		switch splitOpt[0] {
+		case "label":
+			configSpec.Annotations[libpod.InspectAnnotationLabel] = splitOpt[1]
+		case "seccomp":
+			configSpec.Annotations[libpod.InspectAnnotationSeccomp] = splitOpt[1]
+		case "apparmor":
+			configSpec.Annotations[libpod.InspectAnnotationApparmor] = splitOpt[1]
+		}
+	}
+
+	g.SetRootReadonly(c.ReadOnlyRootfs)
+	for sysctlKey, sysctlVal := range c.Sysctl {
+		g.AddLinuxSysctl(sysctlKey, sysctlVal)
+	}
+
+	return nil
+}
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index 33e9ec076d..7a220012f7 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -1,7 +1,6 @@
 package createconfig
 
 import (
-	"os"
 	"strings"
 
 	"github.com/containers/libpod/libpod"
@@ -10,13 +9,11 @@ import (
 	"github.com/containers/libpod/pkg/cgroups"
 	"github.com/containers/libpod/pkg/rootless"
 	"github.com/containers/libpod/pkg/sysinfo"
-	"github.com/docker/docker/oci/caps"
 	"github.com/docker/go-units"
 	"github.com/opencontainers/runc/libcontainer/user"
 	spec "github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/opencontainers/runtime-tools/generate"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 )
 
 const cpuPeriod = 100000
@@ -47,14 +44,13 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
 	canMountSys := true
 
 	isRootless := rootless.IsRootless()
-	hasUserns := config.UsernsMode.IsContainer() || config.UsernsMode.IsNS() || len(config.IDMappings.UIDMap) > 0 || len(config.IDMappings.GIDMap) > 0
-	inUserNS := isRootless || (hasUserns && !config.UsernsMode.IsHost())
+	inUserNS := config.User.InNS(isRootless)
 
-	if inUserNS && config.NetMode.IsHost() {
+	if inUserNS && config.Network.NetMode.IsHost() {
 		canMountSys = false
 	}
 
-	if config.Privileged && canMountSys {
+	if config.Security.Privileged && canMountSys {
 		cgroupPerm = "rw"
 		g.RemoveMount("/sys")
 		sysMnt := spec.Mount{
@@ -68,7 +64,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
 		addCgroup = false
 		g.RemoveMount("/sys")
 		r := "ro"
-		if config.Privileged {
+		if config.Security.Privileged {
 			r = "rw"
 		}
 		sysMnt := spec.Mount{
@@ -78,7 +74,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
 			Options:     []string{"rprivate", "nosuid", "noexec", "nodev", r, "rbind"},
 		}
 		g.AddMount(sysMnt)
-		if !config.Privileged && isRootless {
+		if !config.Security.Privileged && isRootless {
 			g.AddLinuxMaskedPaths("/sys/kernel")
 		}
 	}
@@ -92,9 +88,9 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
 	}
 	// When using a different user namespace, check that the GID 5 is mapped inside
 	// the container.
-	if gid5Available && len(config.IDMappings.GIDMap) > 0 {
+	if gid5Available && len(config.User.IDMappings.GIDMap) > 0 {
 		mappingFound := false
-		for _, r := range config.IDMappings.GIDMap {
+		for _, r := range config.User.IDMappings.GIDMap {
 			if r.ContainerID <= 5 && 5 < r.ContainerID+r.Size {
 				mappingFound = true
 				break
@@ -117,7 +113,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
 		g.AddMount(devPts)
 	}
 
-	if inUserNS && config.IpcMode.IsHost() {
+	if inUserNS && config.Ipc.IpcMode.IsHost() {
 		g.RemoveMount("/dev/mqueue")
 		devMqueue := spec.Mount{
 			Destination: "/dev/mqueue",
@@ -127,7 +123,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
 		}
 		g.AddMount(devMqueue)
 	}
-	if inUserNS && config.PidMode.IsHost() {
+	if inUserNS && config.Pid.PidMode.IsHost() {
 		g.RemoveMount("/proc")
 		procMount := spec.Mount{
 			Destination: "/proc",
@@ -154,55 +150,6 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
 	for key, val := range config.Annotations {
 		g.AddAnnotation(key, val)
 	}
-	g.SetRootReadonly(config.ReadOnlyRootfs)
-
-	if config.HTTPProxy {
-		for _, envSpec := range []string{
-			"http_proxy",
-			"HTTP_PROXY",
-			"https_proxy",
-			"HTTPS_PROXY",
-			"ftp_proxy",
-			"FTP_PROXY",
-			"no_proxy",
-			"NO_PROXY",
-		} {
-			envVal := os.Getenv(envSpec)
-			if envVal != "" {
-				g.AddProcessEnv(envSpec, envVal)
-			}
-		}
-	}
-
-	hostname := config.Hostname
-	if hostname == "" {
-		if utsCtrID := config.UtsMode.Container(); utsCtrID != "" {
-			utsCtr, err := runtime.GetContainer(utsCtrID)
-			if err != nil {
-				return nil, errors.Wrapf(err, "unable to retrieve hostname from dependency container %s", utsCtrID)
-			}
-			hostname = utsCtr.Hostname()
-		} else if config.NetMode.IsHost() || config.UtsMode.IsHost() {
-			hostname, err = os.Hostname()
-			if err != nil {
-				return nil, errors.Wrap(err, "unable to retrieve hostname of the host")
-			}
-		} else {
-			logrus.Debug("No hostname set; container's hostname will default to runtime default")
-		}
-	}
-	g.RemoveHostname()
-	if config.Hostname != "" || !config.UtsMode.IsHost() {
-		// Set the hostname in the OCI configuration only
-		// if specified by the user or if we are creating
-		// a new UTS namespace.
-		g.SetHostname(hostname)
-	}
-	g.AddProcessEnv("HOSTNAME", hostname)
-
-	for sysctlKey, sysctlVal := range config.Sysctl {
-		g.AddLinuxSysctl(sysctlKey, sysctlVal)
-	}
 	g.AddProcessEnv("container", "podman")
 
 	addedResources := false
@@ -272,7 +219,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
 	}
 
 	// Devices
-	if config.Privileged {
+	if config.Security.Privileged {
 		// If privileged, we need to add all the host devices to the
 		// spec.  We do not add the user provided ones because we are
 		// already adding them all.
@@ -287,17 +234,11 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
 		}
 	}
 
-	for _, uidmap := range config.IDMappings.UIDMap {
-		g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size))
-	}
-	for _, gidmap := range config.IDMappings.GIDMap {
-		g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size))
-	}
 	// SECURITY OPTS
-	g.SetProcessNoNewPrivileges(config.NoNewPrivs)
+	g.SetProcessNoNewPrivileges(config.Security.NoNewPrivs)
 
-	if !config.Privileged {
-		g.SetProcessApparmorProfile(config.ApparmorProfile)
+	if !config.Security.Privileged {
+		g.SetProcessApparmorProfile(config.Security.ApparmorProfile)
 	}
 
 	blockAccessToKernelFilesystems(config, &g)
@@ -341,54 +282,35 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
 		return nil, err
 	}
 
-	if err := addPidNS(config, &g); err != nil {
+	// NAMESPACES
+
+	if err := config.Pid.ConfigureGenerator(&g); err != nil {
 		return nil, err
 	}
 
-	if err := addUserNS(config, &g); err != nil {
+	if err := config.User.ConfigureGenerator(&g); err != nil {
 		return nil, err
 	}
 
-	if err := addNetNS(config, &g); err != nil {
+	if err := config.Network.ConfigureGenerator(&g); err != nil {
 		return nil, err
 	}
 
-	if err := addUTSNS(config, &g); err != nil {
+	if err := config.Uts.ConfigureGenerator(&g, &config.Network, runtime); err != nil {
 		return nil, err
 	}
 
-	if err := addIpcNS(config, &g); err != nil {
+	if err := config.Ipc.ConfigureGenerator(&g); err != nil {
 		return nil, err
 	}
 
-	if err := addCgroupNS(config, &g); err != nil {
+	if err := config.Cgroup.ConfigureGenerator(&g); err != nil {
 		return nil, err
 	}
 	configSpec := g.Config
 
-	// HANDLE CAPABILITIES
-	// NOTE: Must happen before SECCOMP
-	if !config.Privileged {
-		if err := setupCapabilities(config, configSpec); err != nil {
-			return nil, err
-		}
-	} else {
-		g.SetupPrivileged(true)
-	}
-
-	// HANDLE SECCOMP
-
-	if config.SeccompProfilePath != "unconfined" {
-		seccompConfig, err := getSeccompConfig(config, configSpec)
-		if err != nil {
-			return nil, err
-		}
-		configSpec.Linux.Seccomp = seccompConfig
-	}
-
-	// Clear default Seccomp profile from Generator for privileged containers
-	if config.SeccompProfilePath == "unconfined" || config.Privileged {
-		configSpec.Linux.Seccomp = nil
+	if err := config.Security.ConfigureGenerator(&g, &config.User); err != nil {
+		return nil, err
 	}
 
 	// BIND MOUNTS
@@ -430,7 +352,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
 		}
 	}
 
-	switch config.Cgroups {
+	switch config.Cgroup.Cgroups {
 	case "disabled":
 		if addedResources {
 			return nil, errors.New("cannot specify resource limits when cgroups are disabled is specified")
@@ -461,48 +383,23 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
 		configSpec.Annotations[libpod.InspectAnnotationVolumesFrom] = strings.Join(config.VolumesFrom, ",")
 	}
 
-	if config.Privileged {
+	if config.Security.Privileged {
 		configSpec.Annotations[libpod.InspectAnnotationPrivileged] = libpod.InspectResponseTrue
 	} else {
 		configSpec.Annotations[libpod.InspectAnnotationPrivileged] = libpod.InspectResponseFalse
 	}
 
-	if config.PublishAll {
-		configSpec.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseTrue
-	} else {
-		configSpec.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseFalse
-	}
-
 	if config.Init {
 		configSpec.Annotations[libpod.InspectAnnotationInit] = libpod.InspectResponseTrue
 	} else {
 		configSpec.Annotations[libpod.InspectAnnotationInit] = libpod.InspectResponseFalse
 	}
 
-	for _, opt := range config.SecurityOpts {
-		// Split on both : and =
-		splitOpt := strings.Split(opt, "=")
-		if len(splitOpt) == 1 {
-			splitOpt = strings.Split(opt, ":")
-		}
-		if len(splitOpt) < 2 {
-			continue
-		}
-		switch splitOpt[0] {
-		case "label":
-			configSpec.Annotations[libpod.InspectAnnotationLabel] = splitOpt[1]
-		case "seccomp":
-			configSpec.Annotations[libpod.InspectAnnotationSeccomp] = splitOpt[1]
-		case "apparmor":
-			configSpec.Annotations[libpod.InspectAnnotationApparmor] = splitOpt[1]
-		}
-	}
-
 	return configSpec, nil
 }
 
 func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator) {
-	if !config.Privileged {
+	if !config.Security.Privileged {
 		for _, mp := range []string{
 			"/proc/acpi",
 			"/proc/kcore",
@@ -518,7 +415,7 @@ func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator)
 			g.AddLinuxMaskedPaths(mp)
 		}
 
-		if config.PidMode.IsHost() && rootless.IsRootless() {
+		if config.Pid.PidMode.IsHost() && rootless.IsRootless() {
 			return
 		}
 
@@ -535,130 +432,6 @@ func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator)
 	}
 }
 
-func addPidNS(config *CreateConfig, g *generate.Generator) error {
-	pidMode := config.PidMode
-	if IsNS(string(pidMode)) {
-		return g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), NS(string(pidMode)))
-	}
-	if pidMode.IsHost() {
-		return g.RemoveLinuxNamespace(string(spec.PIDNamespace))
-	}
-	if pidCtr := pidMode.Container(); pidCtr != "" {
-		logrus.Debugf("using container %s pidmode", pidCtr)
-	}
-	if IsPod(string(pidMode)) {
-		logrus.Debug("using pod pidmode")
-	}
-	return nil
-}
-
-func addUserNS(config *CreateConfig, g *generate.Generator) error {
-	if IsNS(string(config.UsernsMode)) {
-		if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), NS(string(config.UsernsMode))); err != nil {
-			return err
-		}
-		// runc complains if no mapping is specified, even if we join another ns.  So provide a dummy mapping
-		g.AddLinuxUIDMapping(uint32(0), uint32(0), uint32(1))
-		g.AddLinuxGIDMapping(uint32(0), uint32(0), uint32(1))
-	}
-
-	if (len(config.IDMappings.UIDMap) > 0 || len(config.IDMappings.GIDMap) > 0) && !config.UsernsMode.IsHost() {
-		if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-func addNetNS(config *CreateConfig, g *generate.Generator) error {
-	netMode := config.NetMode
-	if netMode.IsHost() {
-		logrus.Debug("Using host netmode")
-		return g.RemoveLinuxNamespace(string(spec.NetworkNamespace))
-	} else if netMode.IsNone() {
-		logrus.Debug("Using none netmode")
-		return nil
-	} else if netMode.IsBridge() {
-		logrus.Debug("Using bridge netmode")
-		return nil
-	} else if netCtr := netMode.Container(); netCtr != "" {
-		logrus.Debugf("using container %s netmode", netCtr)
-		return nil
-	} else if IsNS(string(netMode)) {
-		logrus.Debug("Using ns netmode")
-		return g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), NS(string(netMode)))
-	} else if IsPod(string(netMode)) {
-		logrus.Debug("Using pod netmode, unless pod is not sharing")
-		return nil
-	} else if netMode.IsSlirp4netns() {
-		logrus.Debug("Using slirp4netns netmode")
-		return nil
-	} else if netMode.IsUserDefined() {
-		logrus.Debug("Using user defined netmode")
-		return nil
-	}
-	return errors.Errorf("unknown network mode")
-}
-
-func addUTSNS(config *CreateConfig, g *generate.Generator) error {
-	utsMode := config.UtsMode
-	if IsNS(string(utsMode)) {
-		return g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), NS(string(utsMode)))
-	}
-	if utsMode.IsHost() {
-		return g.RemoveLinuxNamespace(string(spec.UTSNamespace))
-	}
-	if utsCtr := utsMode.Container(); utsCtr != "" {
-		logrus.Debugf("using container %s utsmode", utsCtr)
-	}
-	return nil
-}
-
-func addIpcNS(config *CreateConfig, g *generate.Generator) error {
-	ipcMode := config.IpcMode
-	if IsNS(string(ipcMode)) {
-		return g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), NS(string(ipcMode)))
-	}
-	if ipcMode.IsHost() {
-		return g.RemoveLinuxNamespace(string(spec.IPCNamespace))
-	}
-	if ipcCtr := ipcMode.Container(); ipcCtr != "" {
-		logrus.Debugf("Using container %s ipcmode", ipcCtr)
-	}
-
-	return nil
-}
-
-func addCgroupNS(config *CreateConfig, g *generate.Generator) error {
-	cgroupMode := config.CgroupMode
-
-	if cgroupMode.IsDefaultValue() {
-		// If the value is not specified, default to "private" on cgroups v2 and "host" on cgroups v1.
-		unified, err := cgroups.IsCgroup2UnifiedMode()
-		if err != nil {
-			return err
-		}
-		if unified {
-			cgroupMode = "private"
-		} else {
-			cgroupMode = "host"
-		}
-	}
-	if cgroupMode.IsNS() {
-		return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), NS(string(cgroupMode)))
-	}
-	if cgroupMode.IsHost() {
-		return g.RemoveLinuxNamespace(string(spec.CgroupNamespace))
-	}
-	if cgroupMode.IsPrivate() {
-		return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), "")
-	}
-	if cgCtr := cgroupMode.Container(); cgCtr != "" {
-		logrus.Debugf("Using container %s cgroup mode", cgCtr)
-	}
-	return nil
-}
-
 func addRlimits(config *CreateConfig, g *generate.Generator) error {
 	var (
 		kernelMax  uint64 = 1048576
@@ -702,37 +475,3 @@ func addRlimits(config *CreateConfig, g *generate.Generator) error {
 
 	return nil
 }
-
-func setupCapabilities(config *CreateConfig, configSpec *spec.Spec) error {
-	useNotRoot := func(user string) bool {
-		if user == "" || user == "root" || user == "0" {
-			return false
-		}
-		return true
-	}
-
-	var err error
-	var caplist []string
-	bounding := configSpec.Process.Capabilities.Bounding
-	if useNotRoot(config.User) {
-		configSpec.Process.Capabilities.Bounding = caplist
-	}
-	caplist, err = caps.TweakCapabilities(configSpec.Process.Capabilities.Bounding, config.CapAdd, config.CapDrop, nil, false)
-	if err != nil {
-		return err
-	}
-
-	configSpec.Process.Capabilities.Bounding = caplist
-	configSpec.Process.Capabilities.Permitted = caplist
-	configSpec.Process.Capabilities.Inheritable = caplist
-	configSpec.Process.Capabilities.Effective = caplist
-	configSpec.Process.Capabilities.Ambient = caplist
-	if useNotRoot(config.User) {
-		caplist, err = caps.TweakCapabilities(bounding, config.CapAdd, config.CapDrop, nil, false)
-		if err != nil {
-			return err
-		}
-	}
-	configSpec.Process.Capabilities.Bounding = caplist
-	return nil
-}
diff --git a/pkg/spec/spec_test.go b/pkg/spec/spec_test.go
index 2f91e1b218..0f63b2bbc9 100644
--- a/pkg/spec/spec_test.go
+++ b/pkg/spec/spec_test.go
@@ -21,9 +21,9 @@ var (
 func makeTestCreateConfig() *CreateConfig {
 	cc := new(CreateConfig)
 	cc.Resources = CreateResourceConfig{}
-	cc.IDMappings = new(storage.IDMappingOptions)
-	cc.IDMappings.UIDMap = []idtools.IDMap{}
-	cc.IDMappings.GIDMap = []idtools.IDMap{}
+	cc.User.IDMappings = new(storage.IDMappingOptions)
+	cc.User.IDMappings.UIDMap = []idtools.IDMap{}
+	cc.User.IDMappings.GIDMap = []idtools.IDMap{}
 
 	return cc
 }
diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go
index e30bdfc67d..79c065b5dd 100644
--- a/pkg/spec/storage.go
+++ b/pkg/spec/storage.go
@@ -160,7 +160,7 @@ func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount,
 	}
 
 	// If requested, add tmpfs filesystems for read-only containers.
-	if config.ReadOnlyRootfs && config.ReadOnlyTmpfs {
+	if config.Security.ReadOnlyRootfs && config.Security.ReadOnlyTmpfs {
 		readonlyTmpfs := []string{"/tmp", "/var/tmp", "/run"}
 		options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup"}
 		for _, dest := range readonlyTmpfs {
@@ -807,7 +807,7 @@ func (config *CreateConfig) addContainerInitBinary(path string) (spec.Mount, err
 	if path == "" {
 		return mount, fmt.Errorf("please specify a path to the container-init binary")
 	}
-	if !config.PidMode.IsPrivate() {
+	if !config.Pid.PidMode.IsPrivate() {
 		return mount, fmt.Errorf("cannot add init binary as PID 1 (PID namespace isn't private)")
 	}
 	if config.Systemd {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 138c546c28..a0b361ecd5 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -382,8 +382,8 @@ github.com/opencontainers/runtime-tools/filepath
 github.com/opencontainers/runtime-tools/specerror
 github.com/opencontainers/runtime-tools/error
 # github.com/opencontainers/selinux v1.3.0
-github.com/opencontainers/selinux/go-selinux/label
 github.com/opencontainers/selinux/go-selinux
+github.com/opencontainers/selinux/go-selinux/label
 # github.com/openshift/api v3.9.1-0.20190810003144-27fb16909b15+incompatible
 github.com/openshift/api/config/v1
 # github.com/openshift/imagebuilder v1.1.1