Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docker_image_history table #6884

Merged
merged 1 commit into from Jan 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
80 changes: 79 additions & 1 deletion osquery/tables/applications/posix/docker.cpp
Expand Up @@ -1018,7 +1018,7 @@ QueryData genVolumeLabels(QueryContext& context) {
/**
* @brief Image layer extractor for docker_image_layers table
*/
void getImageLayers(std::string image_id, QueryData& results) {
void getImageLayers(const std::string& image_id, QueryData& results) {
pt::ptree tree;
std::vector<std::string> layers;

Expand Down Expand Up @@ -1096,6 +1096,84 @@ QueryData genImageLayers(QueryContext& context) {
return results;
}

/**
* @brief Image history extractor for docker_image_history table
*/
void getImageHistory(const std::string& image_id, QueryData& results) {
pt::ptree tree;
Status s = dockerApi("/images/" + image_id + "/history", tree);
if (!s.ok()) {
VLOG(1) << "Error getting docker images history: " << s.what();
return;
}

for (const auto& entry : tree) {
try {
const pt::ptree& node = entry.second;
std::string tags;
for (const auto& tag : node.get_child("Tags")) {
if (!tags.empty()) {
tags.append(",");
}
tags.append(tag.second.data());
}

Row r;
r["id"] = image_id;
r["created"] = BIGINT(node.get<uint64_t>("Created", 0));
r["size"] = BIGINT(node.get<uint64_t>("Size", 0));
r["created_by"] = node.get<std::string>("CreatedBy", "");
r["tags"] = tags;
r["comment"] = node.get<std::string>("Comment", "");
results.push_back(r);
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error getting docker image history: " << e.what();
}
}
}

/**
* @brief Calls history for all images for docker_image_history table
*/
void getImageHistoryAll(QueryData& results) {
pt::ptree tree;
Status s = dockerApi("/images/json", tree);
if (!s.ok()) {
VLOG(1) << "Error getting docker images: " << s.what();
return;
}
for (const auto& entry : tree) {
try {
const pt::ptree& node = entry.second;
std::string id = node.get<std::string>("Id", "");
if (boost::starts_with(id, "sha256:")) {
id.erase(0, 7);
}
getImageHistory(id, results);
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error getting docker image history: " << e.what();
}
}
}

/**
* @brief Entry point for docker_image_history table.
*/
QueryData genImageHistory(QueryContext& context) {
QueryData results;
if (context.constraints["id"].exists(EQUALS)) {
for (const auto& id : context.constraints["id"].getAll(EQUALS)) {
if (!checkConstraintValue(id)) {
continue;
}
getImageHistory(id, results);
}
} else {
getImageHistoryAll(results);
}
return results;
}

/**
* @brief Entry point for docker_images table.
*/
Expand Down
1 change: 1 addition & 0 deletions specs/CMakeLists.txt
Expand Up @@ -197,6 +197,7 @@ function(generateNativeTables)
"posix/docker_container_fs_changes.table:linux,macos,freebsd"
"posix/docker_container_stats.table:linux,macos,freebsd"
"posix/docker_containers.table:linux,macos,freebsd"
"posix/docker_image_history.table:linux,macos,freebsd"
"posix/docker_image_labels.table:linux,macos,freebsd"
"posix/docker_image_layers.table:linux,macos,freebsd"
"posix/docker_images.table:linux,macos,freebsd"
Expand Down
16 changes: 16 additions & 0 deletions specs/posix/docker_image_history.table
@@ -0,0 +1,16 @@
table_name("docker_image_history")
description("Docker image history information.")
schema([
Column("id", TEXT, "Image ID", index=True),
Column("created", BIGINT, "Time of creation as UNIX time"),
Column("size", BIGINT, "Size of instruction in bytes"),
Column("created_by", TEXT, "Created by instruction"),
Column("tags", TEXT, "Comma-separated list of tags"),
Column("comment", TEXT, "Instruction comment")
])
implementation("applications/docker@genImageHistory")
examples([
"select * from docker_image_history",
"select * from docker_image_history where id = '6a2f32de169d'",
"select * from docker_image_history where id = '6a2f32de169d14e6f8a84538eaa28f2629872d7d4f580a303b296c60db36fbd7'"
])
1 change: 1 addition & 0 deletions tests/integration/tables/CMakeLists.txt
Expand Up @@ -96,6 +96,7 @@ function(generateTestsIntegrationTablesTestsTest)
docker_container_processes.cpp
docker_container_stats.cpp
docker_containers.cpp
docker_image_history.cpp
docker_image_labels.cpp
docker_image_layers.cpp
docker_images.cpp
Expand Down
44 changes: 44 additions & 0 deletions tests/integration/tables/docker_image_history.cpp
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2014-present, The osquery authors
*
* This source code is licensed as defined by the LICENSE file found in the
* root directory of this source tree.
*
* SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only)
*/

// Sanity check integration test for docker_image_history
// Spec file: specs/posix/docker_image_history.table

#include <osquery/tests/integration/tables/helper.h>

namespace osquery {
namespace table_tests {

class dockerImageHistoryTest : public testing::Test {
void SetUp() override {
setUpEnvironment();
}
};

TEST_F(dockerImageHistoryTest, test_sanity) {
QueryData data = execute_query("select * from docker_images");
if (data.size() <= 0) { // docker not installed, or issues talking to dockerd,
// or no images present
return;
}

data = execute_query("select * from docker_image_history");
ASSERT_GT(data.size(), 0ul);
ValidationMap row_map = {
{"id", NonEmptyString},
{"created", NonNegativeInt},
{"size", NonNegativeInt},
{"created_by", NormalType},
{"tags", NormalType},
{"comment", NormalType},
};
validate_rows(data, row_map);
}
} // namespace table_tests
} // namespace osquery