Skip to content
This repository was archived by the owner on Feb 12, 2022. It is now read-only.

Commit 635c0e3

Browse files
author
Pavlo Kolomiiets
committed
Add IoT cert/key authentication method
1 parent ad90140 commit 635c0e3

File tree

5 files changed

+215
-5
lines changed

5 files changed

+215
-5
lines changed

kinesis_video_streamer/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ catkin_package()
2828
## Build ##
2929
###########
3030
## Declare a C++ executable
31-
set(KINESIS_VIDEO_STREAMER_SRC src/ros_stream_subscription_installer.cpp src/subscriber_callbacks.cpp src/streamer.cpp)
31+
set(KINESIS_VIDEO_STREAMER_SRC src/ros_stream_subscription_installer.cpp src/subscriber_callbacks.cpp src/streamer.cpp src/credentials.cpp)
3232
add_executable(${PROJECT_NAME} src/main.cpp ${KINESIS_VIDEO_STREAMER_SRC})
3333
add_library(${PROJECT_NAME}_lib ${KINESIS_VIDEO_STREAMER_SRC})
3434
## Specify include directories

kinesis_video_streamer/config/node_sample_configuration.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
# This is the AWS IoT Credentials Provider configuration, used as 1st priority authentication method if valid.
2+
iot:
3+
# Path to the Root CA for the endpoint
4+
#cafile: ""
5+
6+
# Path to the certificate which identifies the device
7+
#certfile: ""
8+
9+
# Path to the related private key for the certificate
10+
#keyfile: ""
11+
12+
# Thing name for the device
13+
#thing_name: ""
14+
15+
# Host name of the iot:CredentialProvider endpoint
16+
#endpoint: ""
17+
18+
# Name of the AWS IoT Role Alias for the device
19+
#role: ""
20+
121
# This is the AWS Client Configuration used by the AWS service client in the Node. If given the node will load the
222
# provided configuration when initializing the client.
323
aws_client_configuration:
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#pragma once
2+
3+
#include <aws/core/auth/AWSCredentialsProviderChain.h>
4+
#include <aws_common/sdk_utils/auth/service_credentials_provider.h>
5+
#include <kinesis-video-producer/Auth.h>
6+
7+
namespace Aws
8+
{
9+
namespace Auth
10+
{
11+
/**
12+
* Creates an AWSCredentialsProviderChain which uses in order IotRoleCredentialsProvider and EnvironmentAWSCredentialsProvider.
13+
*/
14+
class CustomAWSCredentialsProviderChain : public AWSCredentialsProviderChain
15+
{
16+
public:
17+
CustomAWSCredentialsProviderChain() = default;
18+
19+
/**
20+
* Initializes the provider chain with IotRoleCredentialsProvider and EnvironmentAWSCredentialsProvider in that order.
21+
*
22+
* @param config Configuration for available credential providers
23+
*/
24+
CustomAWSCredentialsProviderChain(const ServiceAuthConfig &config);
25+
};
26+
27+
} // namespace Auth
28+
} // namespace Aws
29+
30+
31+
namespace Aws {
32+
namespace Kinesis {
33+
/**
34+
* Credentials provider which uses the AWS SDK's default credential provider chain.
35+
* @note You need to have called Aws::InitAPI before using this provider.
36+
*/
37+
class CustomProducerSdkAWSCredentialsProvider : public com::amazonaws::kinesis::video::CredentialProvider
38+
{
39+
public:
40+
CustomProducerSdkAWSCredentialsProvider(std::shared_ptr<Aws::Auth::AWSCredentialsProvider>
41+
aws_credentials_provider = nullptr);
42+
private:
43+
std::shared_ptr<Aws::Auth::AWSCredentialsProvider> aws_credentials_provider_;
44+
45+
void updateCredentials(com::amazonaws::kinesis::video::Credentials & producer_sdk_credentials) override;
46+
};
47+
48+
} // namespace Kinesis
49+
} // namespace Aws
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#include <aws/core/platform/Environment.h>
2+
#include <aws/core/utils/logging/LogMacros.h>
3+
4+
#include <kinesis_video_streamer/credentials.h>
5+
6+
using namespace Aws::Auth;
7+
8+
/// Logging tag used for all messages emitting from this module
9+
static const char AWS_LOG_TAG[] = "CustomAWSCredentialsProviderChain";
10+
static const char AWS_ECS_CONTAINER_CREDENTIALS_RELATIVE_URI[] = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI";
11+
static const char AWS_ECS_CONTAINER_CREDENTIALS_FULL_URI[] = "AWS_CONTAINER_CREDENTIALS_FULL_URI";
12+
static const char AWS_ECS_CONTAINER_AUTHORIZATION_TOKEN[] = "AWS_CONTAINER_AUTHORIZATION_TOKEN";
13+
static const char AWS_EC2_METADATA_DISABLED[] = "AWS_EC2_METADATA_DISABLED";
14+
15+
namespace Aws
16+
{
17+
namespace Auth
18+
{
19+
20+
/**
21+
* \brief Validates an instance of an IotRoleConfig struct
22+
* @param config The struct to validate
23+
* @return True if the struct is valid, meaning all the config needed to connect is there
24+
*/
25+
static bool IsIotConfigValid(const IotRoleConfig & config)
26+
{
27+
return config.cafile.length() > 0 && config.certfile.length() > 0 &&
28+
config.keyfile.length() > 0 && config.host.length() > 0 && config.role.length() > 0 &&
29+
config.name.length() > 0 && config.connect_timeout_ms > 0 && config.total_timeout_ms > 0;
30+
}
31+
32+
CustomAWSCredentialsProviderChain::CustomAWSCredentialsProviderChain(const ServiceAuthConfig &config):
33+
AWSCredentialsProviderChain()
34+
{
35+
// Add IoT credentials provider if valid
36+
if (IsIotConfigValid(config.iot)) {
37+
AWS_LOG_INFO(AWS_LOG_TAG, "Found valid IoT auth config, adding IotRoleCredentialsProvider");
38+
auto provider = Aws::MakeShared<IotRoleCredentialsProvider>(__func__, config.iot);
39+
AddProvider(provider);
40+
} else {
41+
AWS_LOG_INFO(AWS_LOG_TAG, "No valid IoT auth config, skipping IotRoleCredentialsProvider");
42+
}
43+
44+
// Add environment credentials provider
45+
AddProvider(Aws::MakeShared<EnvironmentAWSCredentialsProvider>(AWS_LOG_TAG));
46+
AddProvider(Aws::MakeShared<ProfileConfigFileAWSCredentialsProvider>(AWS_LOG_TAG));
47+
48+
//ECS TaskRole Credentials only available when ENVIRONMENT VARIABLE is set
49+
const auto relativeUri = Aws::Environment::GetEnv(AWS_ECS_CONTAINER_CREDENTIALS_RELATIVE_URI);
50+
AWS_LOGSTREAM_DEBUG(AWS_LOG_TAG, "The environment variable value " << AWS_ECS_CONTAINER_CREDENTIALS_RELATIVE_URI
51+
<< " is " << relativeUri);
52+
53+
const auto absoluteUri = Aws::Environment::GetEnv(AWS_ECS_CONTAINER_CREDENTIALS_FULL_URI);
54+
AWS_LOGSTREAM_DEBUG(AWS_LOG_TAG, "The environment variable value " << AWS_ECS_CONTAINER_CREDENTIALS_FULL_URI
55+
<< " is " << absoluteUri);
56+
57+
const auto ec2MetadataDisabled = Aws::Environment::GetEnv(AWS_EC2_METADATA_DISABLED);
58+
AWS_LOGSTREAM_DEBUG(AWS_LOG_TAG, "The environment variable value " << AWS_EC2_METADATA_DISABLED
59+
<< " is " << ec2MetadataDisabled);
60+
61+
if (!relativeUri.empty())
62+
{
63+
AddProvider(Aws::MakeShared<TaskRoleCredentialsProvider>(AWS_LOG_TAG, relativeUri.c_str()));
64+
AWS_LOGSTREAM_INFO(AWS_LOG_TAG, "Added ECS metadata service credentials provider with relative path: ["
65+
<< relativeUri << "] to the provider chain.");
66+
}
67+
else if (!absoluteUri.empty())
68+
{
69+
const auto token = Aws::Environment::GetEnv(AWS_ECS_CONTAINER_AUTHORIZATION_TOKEN);
70+
AddProvider(Aws::MakeShared<TaskRoleCredentialsProvider>(AWS_LOG_TAG,
71+
absoluteUri.c_str(), token.c_str()));
72+
73+
//DO NOT log the value of the authorization token for security purposes.
74+
AWS_LOGSTREAM_INFO(AWS_LOG_TAG, "Added ECS credentials provider with URI: ["
75+
<< absoluteUri << "] to the provider chain with a" << (token.empty() ? "n empty " : " non-empty ")
76+
<< "authorization token.");
77+
}
78+
else if (Aws::Utils::StringUtils::ToLower(ec2MetadataDisabled.c_str()) != "true")
79+
{
80+
AddProvider(Aws::MakeShared<InstanceProfileCredentialsProvider>(AWS_LOG_TAG));
81+
AWS_LOGSTREAM_INFO(AWS_LOG_TAG, "Added EC2 metadata service credentials provider to the provider chain.");
82+
}
83+
}
84+
85+
} // namespace Auth
86+
} // namespace Aws
87+
88+
namespace Aws {
89+
namespace Kinesis {
90+
/**
91+
* Credentials provider which uses the AWS SDK's default credential provider chain.
92+
* @note You need to have called Aws::InitAPI before using this provider.
93+
*/
94+
CustomProducerSdkAWSCredentialsProvider::CustomProducerSdkAWSCredentialsProvider(
95+
std::shared_ptr<Aws::Auth::AWSCredentialsProvider> aws_credentials_provider)
96+
{
97+
if (aws_credentials_provider) {
98+
aws_credentials_provider_ = aws_credentials_provider;
99+
} else {
100+
aws_credentials_provider_ =
101+
Aws::MakeShared<Aws::Auth::DefaultAWSCredentialsProviderChain>(__func__);
102+
}
103+
}
104+
105+
void CustomProducerSdkAWSCredentialsProvider::updateCredentials(
106+
com::amazonaws::kinesis::video::Credentials & producer_sdk_credentials)
107+
{
108+
Aws::Auth::AWSCredentials aws_sdk_credentials =
109+
aws_credentials_provider_->GetAWSCredentials();
110+
producer_sdk_credentials.setAccessKey(aws_sdk_credentials.GetAWSAccessKeyId().c_str());
111+
producer_sdk_credentials.setSecretKey(aws_sdk_credentials.GetAWSSecretKey().c_str());
112+
producer_sdk_credentials.setSessionToken(aws_sdk_credentials.GetSessionToken().c_str());
113+
auto now = std::chrono::duration_cast<std::chrono::seconds>(
114+
std::chrono::system_clock::now().time_since_epoch());
115+
auto refresh_interval = std::chrono::duration_cast<std::chrono::seconds>(
116+
std::chrono::milliseconds(Aws::Auth::REFRESH_THRESHOLD));
117+
producer_sdk_credentials.setExpiration(now + refresh_interval);
118+
}
119+
120+
} // namespace Kinesis
121+
} // namespace Aws

kinesis_video_streamer/src/streamer.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@
2121
#include <aws_common/sdk_utils/client_configuration_provider.h>
2222
#include <aws_ros1_common/sdk_utils/logging/aws_ros_logger.h>
2323
#include <aws_ros1_common/sdk_utils/ros1_node_parameter_reader.h>
24+
#include <kinesis_manager/default_callbacks.h>
25+
#include <kinesis_video_streamer/credentials.h>
2426
#include <kinesis_video_streamer/ros_stream_subscription_installer.h>
2527
#include <kinesis_video_streamer/streamer.h>
2628
#include <kinesis_video_streamer/subscriber_callbacks.h>
2729
#include <ros/ros.h>
2830

2931
using namespace Aws::Client;
3032
using namespace Aws::Kinesis;
33+
using namespace com::amazonaws::kinesis::video;
3134

3235

3336
#ifndef RETURN_CODE_MASK
@@ -71,15 +74,32 @@ KinesisManagerStatus StreamerNode::Initialize()
7174
AWS_LOG_FATAL(__func__, "Failed to set up subscription callbacks.");
7275
return KINESIS_MANAGER_STATUS_ERROR_BASE;
7376
}
74-
auto kinesis_client = std::unique_ptr<KinesisClient>(
75-
Aws::New<Aws::Kinesis::KinesisClientFacade>(__func__, aws_sdk_config));
77+
Aws::Auth::ServiceAuthConfig aws_ros_config;
78+
Aws::Auth::GetServiceAuthConfig(aws_ros_config, parameter_reader_);
79+
auto aws_credentials_provider = Aws::MakeShared<Aws::Auth::CustomAWSCredentialsProviderChain>(__func__, aws_ros_config);
80+
auto kinesis_client = std::make_unique<KinesisClient>(aws_credentials_provider, aws_sdk_config);
7681
stream_manager_ = std::make_shared<KinesisStreamManager>(
7782
parameter_reader_.get(), &stream_definition_provider_, subscription_installer_.get(),
7883
std::move(kinesis_client));
7984
subscription_installer_->set_stream_manager(stream_manager_.get());
8085
/* Initialization of video producer */
81-
KinesisManagerStatus initialize_video_producer_result =
82-
stream_manager_->InitializeVideoProducer(aws_sdk_config.region.c_str());
86+
auto credentials_provider = std::make_unique<CustomProducerSdkAWSCredentialsProvider>(aws_credentials_provider);
87+
KinesisManagerStatus initialize_video_producer_result;
88+
if (!credentials_provider) {
89+
AWS_LOG_ERROR(__func__,
90+
"Credential provider is invalid, have you set the environment variables required "
91+
"for AWS access?");
92+
initialize_video_producer_result = KINESIS_MANAGER_STATUS_DEFAULT_CREDENTIAL_PROVIDER_CREATION_FAILED;
93+
}
94+
else {
95+
auto device_provider = std::make_unique<DefaultDeviceInfoProvider>();
96+
auto client_callback_provider = std::make_unique<DefaultClientCallbackProvider>();
97+
auto stream_callback_provider = std::make_unique<DefaultStreamCallbackProvider>();
98+
initialize_video_producer_result =
99+
stream_manager_->InitializeVideoProducer(aws_sdk_config.region.c_str(),
100+
std::move(device_provider), std::move(client_callback_provider),
101+
std::move(stream_callback_provider), std::move(credentials_provider));
102+
}
83103
if (KINESIS_MANAGER_STATUS_FAILED(initialize_video_producer_result)) {
84104
fprintf(stderr, "Failed to initialize video producer");
85105
AWS_LOGSTREAM_FATAL(__func__, "Failed to initialize video producer. Error code: "

0 commit comments

Comments
 (0)