// +build !windows package authz // import "github.com/docker/docker/integration/plugin/authz" import ( "context" "fmt" "io/ioutil" "os" "strings" "testing" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" volumetypes "github.com/docker/docker/api/types/volume" "github.com/docker/docker/client" "github.com/docker/docker/integration/internal/container" "github.com/docker/docker/integration/internal/requirement" "github.com/gotestyourself/gotestyourself/skip" "github.com/stretchr/testify/require" ) var ( authzPluginName = "riyaz/authz-no-volume-plugin" authzPluginTag = "latest" authzPluginNameWithTag = authzPluginName + ":" + authzPluginTag authzPluginBadManifestName = "riyaz/authz-plugin-bad-manifest" nonexistentAuthzPluginName = "riyaz/nonexistent-authz-plugin" ) func setupTestV2(t *testing.T) func() { skip.IfCondition(t, testEnv.DaemonInfo.OSType != "linux") skip.IfCondition(t, !requirement.HasHubConnectivity(t)) teardown := setupTest(t) d.Start(t) return teardown } func TestAuthZPluginV2AllowNonVolumeRequest(t *testing.T) { skip.IfCondition(t, os.Getenv("DOCKER_ENGINE_GOARCH") != "amd64") defer setupTestV2(t)() client, err := d.NewClient() require.Nil(t, err) ctx := context.Background() // Install authz plugin err = pluginInstallGrantAllPermissions(client, authzPluginNameWithTag) require.Nil(t, err) // start the daemon with the plugin and load busybox, --net=none build fails otherwise // because it needs to pull busybox d.Restart(t, "--authorization-plugin="+authzPluginNameWithTag) d.LoadBusybox(t) // Ensure docker run command and accompanying docker ps are successful cID := container.Run(t, ctx, client) _, err = client.ContainerInspect(ctx, cID) require.Nil(t, err) } func TestAuthZPluginV2Disable(t *testing.T) { skip.IfCondition(t, os.Getenv("DOCKER_ENGINE_GOARCH") != "amd64") defer setupTestV2(t)() client, err := d.NewClient() require.Nil(t, err) // Install authz plugin err = pluginInstallGrantAllPermissions(client, authzPluginNameWithTag) require.Nil(t, err) d.Restart(t, "--authorization-plugin="+authzPluginNameWithTag) d.LoadBusybox(t) _, err = client.VolumeCreate(context.Background(), volumetypes.VolumesCreateBody{Driver: "local"}) require.NotNil(t, err) require.True(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))) // disable the plugin err = client.PluginDisable(context.Background(), authzPluginNameWithTag, types.PluginDisableOptions{}) require.Nil(t, err) // now test to see if the docker api works. _, err = client.VolumeCreate(context.Background(), volumetypes.VolumesCreateBody{Driver: "local"}) require.Nil(t, err) } func TestAuthZPluginV2RejectVolumeRequests(t *testing.T) { skip.IfCondition(t, os.Getenv("DOCKER_ENGINE_GOARCH") != "amd64") defer setupTestV2(t)() client, err := d.NewClient() require.Nil(t, err) // Install authz plugin err = pluginInstallGrantAllPermissions(client, authzPluginNameWithTag) require.Nil(t, err) // restart the daemon with the plugin d.Restart(t, "--authorization-plugin="+authzPluginNameWithTag) _, err = client.VolumeCreate(context.Background(), volumetypes.VolumesCreateBody{Driver: "local"}) require.NotNil(t, err) require.True(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))) _, err = client.VolumeList(context.Background(), filters.Args{}) require.NotNil(t, err) require.True(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))) // The plugin will block the command before it can determine the volume does not exist err = client.VolumeRemove(context.Background(), "test", false) require.NotNil(t, err) require.True(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))) _, err = client.VolumeInspect(context.Background(), "test") require.NotNil(t, err) require.True(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))) _, err = client.VolumesPrune(context.Background(), filters.Args{}) require.NotNil(t, err) require.True(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))) } func TestAuthZPluginV2BadManifestFailsDaemonStart(t *testing.T) { skip.IfCondition(t, os.Getenv("DOCKER_ENGINE_GOARCH") != "amd64") defer setupTestV2(t)() client, err := d.NewClient() require.Nil(t, err) // Install authz plugin with bad manifest err = pluginInstallGrantAllPermissions(client, authzPluginBadManifestName) require.Nil(t, err) // start the daemon with the plugin, it will error err = d.RestartWithError("--authorization-plugin=" + authzPluginBadManifestName) require.NotNil(t, err) // restarting the daemon without requiring the plugin will succeed d.Start(t) } func TestAuthZPluginV2NonexistentFailsDaemonStart(t *testing.T) { defer setupTestV2(t)() // start the daemon with a non-existent authz plugin, it will error err := d.RestartWithError("--authorization-plugin=" + nonexistentAuthzPluginName) require.NotNil(t, err) // restarting the daemon without requiring the plugin will succeed d.Start(t) } func pluginInstallGrantAllPermissions(client client.APIClient, name string) error { ctx := context.Background() options := types.PluginInstallOptions{ RemoteRef: name, AcceptAllPermissions: true, } responseReader, err := client.PluginInstall(ctx, "", options) if err != nil { return err } defer responseReader.Close() // we have to read the response out here because the client API // actually starts a goroutine which we can only be sure has // completed when we get EOF from reading responseBody _, err = ioutil.ReadAll(responseReader) return err }