| #ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_AUTHZ_AUTHZ_SERVER_H_ |
| #define THIRD_PARTY_MILOTIC_EXTERNAL_CC_AUTHZ_AUTHZ_SERVER_H_ |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstdlib> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| |
| #include "absl/base/thread_annotations.h" |
| #include "absl/synchronization/mutex.h" |
| #include "grpcpp/security/auth_context.h" |
| #include "grpcpp/server.h" |
| #include "grpcpp/server_builder.h" |
| #include "grpcpp/support/status.h" |
| #include "config_parser.h" |
| #include "oauth.grpc.pb.h" |
| #include "oauth.pb.h" |
| |
| namespace milotic::authz { |
| // ssh-keygen user certificate sign command template take parameters: |
| // {0}: port_id |
| // {1}: life_time_in_seconds |
| // {2}: the public key file |
| constexpr std::string_view kHiscCertGenCmd = |
| R"delim(/usr/bin/ssh-keygen \ |
| -s /run/hiscd/hiscd_ca \ |
| -I "port-{0}@$(hostname)" \ |
| -z "$(date +%s)" \ |
| -n "hisc" \ |
| -V "+{1}s" \ |
| -O clear -O permit-pty \ |
| -O force-command='/usr/libexec/ttf-console.sh -s user port-{0}' \ |
| {2} 2>&1 | /usr/bin/systemd-cat -t hisc_token -p info |
| )delim"; |
| |
| // The maximum life time in seconds of Host Interactive Serial Console token. |
| constexpr uint32_t kMaxHiscCertLifeTimeInSeconds = 30 * 60; // 30 mins |
| |
| // The system dependency of HiscToken RPC |
| class HiscTokenSystemDependency { |
| public: |
| virtual ~HiscTokenSystemDependency() = default; |
| virtual int LibcMkstemp(char tmpname[]) = 0; |
| virtual int RunSshKeyGen(const std::string& cmd, |
| std::string_view input_key_file) = 0; |
| }; |
| |
| // This class is thread-safe. The thread safety is provided by the system |
| // functions it calls and the cmd it runs which are thread-safe. |
| class BMCHiscTokenSystemDependency : public HiscTokenSystemDependency { |
| public: |
| int LibcMkstemp(char tmpname[]) override { return mkstemp(tmpname); } |
| int RunSshKeyGen(const std::string& cmd, |
| [[maybe_unused]] std::string_view input_key_file) override { |
| return std::system(cmd.c_str()); |
| } |
| }; |
| // The AuthorizationServer only works in mutual TLS mode. |
| struct ServerConfiguration { |
| int port = 0; |
| // The credentials used in the gRPC interface. |
| std::string trust_bundle_path; |
| std::string server_certificate_path; |
| std::string server_key_path; |
| std::string server_fqdn; |
| std::string authz_configuration_path; |
| std::string crl_directory; |
| |
| // The absolute path where Offline Node Entities file is. (Can be left empty) |
| // This should be the file installed on the node during RRI |
| // For more information see go/node-entities-api |
| std::string offline_node_entities_path; |
| |
| // The path where the Google Machine Identity is. If left empty, machines in |
| // HWOPS may be configured incorrectly. For more information see |
| // go/google-machine-identity-token |
| std::string google_machine_identity_path; |
| |
| // The path where the server will dump the public key for other processes. |
| std::string rsa_public_key_path; |
| }; |
| |
| namespace impl { |
| |
| class AuthorizationServiceImpl : public ::oauth::AuthorizationService::Service { |
| public: |
| explicit AuthorizationServiceImpl(const ServerConfiguration& server_config); |
| |
| grpc::Status Exchange(::grpc::ServerContext* /*context*/, |
| const ::oauth::ExchangeRequest* /*request*/, |
| ::oauth::ExchangeResponse* /*response*/) override; |
| |
| grpc::Status MintToken(::grpc::ServerContext* context, |
| const ::oauth::MintTokenRequest* request, |
| ::oauth::MintTokenResponse* response) override; |
| |
| grpc::Status HiscToken(::grpc::ServerContext* context, |
| const ::oauth::HiscTokenRequest* request, |
| ::oauth::HiscTokenResponse* response) override; |
| |
| ~AuthorizationServiceImpl() override = default; |
| |
| void LoadAuthzConfig(); |
| |
| std::string GetRsaPrivateKey() const { return rsa_private_key_; } |
| |
| std::string GetServerFqdn(); |
| |
| void SetServerFqdn(const std::string& server_fqdn); |
| |
| protected: |
| grpc::Status AuthorizeMintTokenRpc(const grpc::AuthContext& context); |
| |
| grpc::Status CheckMintTokenRequest(const ::oauth::MintTokenRequest& request); |
| |
| std::string GetAndIncreaseTokenCount(); |
| |
| grpc::Status AuthorizeHiscTokenRpc(const grpc::AuthContext& context); |
| |
| static grpc::Status HiscToken( |
| const ::oauth::HiscTokenRequest* request, |
| ::oauth::HiscTokenResponse* response, |
| HiscTokenSystemDependency& hisc_token_system_dependency); |
| |
| private: |
| std::unique_ptr<AuthzConfiguration> authz_config_; |
| std::string rsa_private_key_; |
| |
| absl::Mutex mutex_; |
| std::size_t token_count_ ABSL_GUARDED_BY(mutex_); |
| ServerConfiguration server_config_ ABSL_GUARDED_BY(mutex_); |
| BMCHiscTokenSystemDependency bmc_hisc_token_system_dependency_; |
| }; |
| |
| } // namespace impl |
| |
| // The BMC local authorization server. |
| // This class is thread-safe. |
| class AuthorizationServer { |
| public: |
| explicit AuthorizationServer(const ServerConfiguration& config); |
| ~AuthorizationServer(); |
| |
| void StartServer(); |
| |
| // Thread safe reload on authz config without updating the RSA key |
| void ReloadAuthzConfig(const std::string& server_fqdn); |
| |
| // Blocks until process is killed. |
| void Wait(); |
| |
| std::string GetRsaPrivateKey() const { return service_->GetRsaPrivateKey(); } |
| |
| private: |
| ServerConfiguration server_config_; |
| std::unique_ptr<impl::AuthorizationServiceImpl> service_; |
| std::unique_ptr<grpc::Server> server_; |
| }; |
| |
| } // namespace milotic::authz |
| #endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_AUTHZ_AUTHZ_SERVER_H_ |