| #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 "config_parser.h" | |
| #include "oauth.grpc.pb.h" | |
| #include "oauth.pb.h" | |
| #include "g3/grpc_headers.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_ |