Skip to content

Commit 534f839

Browse files
authored
[ycabled] add support for getting grpc secerts via shared file (sonic-net#298)
This PR adds support for adding the secrets to grpc client in active-active configuration via a shared file /etc/sonic/grpc_secrets.json. Using this file, secrets configuration in populated inside CONFIG_DB, absence of this file will assume insecure gRPC client. Description Motivation and Context How Has This Been Tested? testing with UT and putting the changes on Arista testbed Signed-off-by: vaibhav-dahiya [email protected]
1 parent 3622aac commit 534f839

File tree

2 files changed

+77
-5
lines changed

2 files changed

+77
-5
lines changed

sonic-ycabled/tests/test_y_cable_helper.py

+18-2
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
import time
1111

1212
if sys.version_info >= (3, 3):
13-
from unittest.mock import MagicMock, patch
13+
from unittest.mock import MagicMock, patch, mock_open
1414
else:
15-
from mock import MagicMock, patch
15+
from mock import MagicMock, patch, mock_open
1616

1717

1818
daemon_base.db_connect = MagicMock()
@@ -5458,6 +5458,7 @@ def test_get_mux_cable_static_info_without_presence(self):
54585458
assert(rc['nic_lane1_postcursor1'] == 'N/A')
54595459
assert(rc['nic_lane1_postcursor2'] == 'N/A')
54605460

5461+
@patch('os.path.isfile', MagicMock(return_value=True))
54615462
def test_get_grpc_credentials(self):
54625463

54635464
kvp = {}
@@ -5469,6 +5470,7 @@ def test_get_grpc_credentials(self):
54695470

54705471

54715472
@patch('builtins.open')
5473+
@patch('os.path.isfile', MagicMock(return_value=True))
54725474
def test_get_grpc_credentials_root(self, open):
54735475

54745476
kvp = {"ca_crt": "file"}
@@ -5498,3 +5500,17 @@ def test_handle_ycable_enable_disable_tel_notification_probe(self):
54985500
fvp_m = {"log_verbosity": "debug"}
54995501
rc = handle_ycable_enable_disable_tel_notification(fvp_m, "Y_CABLE")
55005502
assert(rc == None)
5503+
5504+
5505+
@patch('builtins.open')
5506+
def test_apply_grpc_secrets_configuration(self, open):
5507+
5508+
parsed_data = {'GRPCCLIENT': {'config': {'type': 'secure', 'auth_level': 'server', 'log_level': 'info'}, 'certs': {'client_crt': 'one.crt', 'client_key': 'one.key', 'ca_crt': 'ss.crt', 'grpc_ssl_credential': 'jj.tsl'}}}
5509+
5510+
mock_file = MagicMock()
5511+
open.return_value = mock_file
5512+
#json_load.return_value = parsed_data
5513+
with patch('json.load') as patched_util:
5514+
patched_util.return_value = parsed_data
5515+
rc = apply_grpc_secrets_configuration(None)
5516+
assert(rc == None)

sonic-ycabled/ycable/ycable_utilities/y_cable_helper.py

+59-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import datetime
77
import ipaddress
8+
import json
89
import os
910
import re
1011
import sys
@@ -115,6 +116,8 @@
115116
PORT_INSTANCE_ERROR
116117
}
117118

119+
SECRETS_PATH = "/etc/sonic/grpc_secrets.json"
120+
118121
def format_mapping_identifier(string):
119122
"""
120123
Takes an arbitrary string and creates a valid entity for port mapping file.
@@ -369,26 +372,64 @@ def retry_setup_grpc_channel_for_port(port, asic_index):
369372
grpc_port_stubs[port] = stub
370373
return True
371374

375+
def apply_grpc_secrets_configuration(SECRETS_PATH):
376+
377+
378+
f = open(SECRETS_PATH, 'rb')
379+
parsed_data = json.load(f)
380+
381+
config_db, grpc_config = {}, {}
382+
namespaces = multi_asic.get_front_end_namespaces()
383+
for namespace in namespaces:
384+
asic_id = multi_asic.get_asic_index_from_namespace(namespace)
385+
config_db[asic_id] = daemon_base.db_connect("CONFIG_DB", namespace)
386+
grpc_config[asic_id] = swsscommon.Table(config_db[asic_id], "GRPCCLIENT")
387+
388+
389+
asic_index = multi_asic.get_asic_index_from_namespace(DEFAULT_NAMESPACE)
390+
grpc_client_config = parsed_data.get("GRPCCLIENT", None)
391+
if grpc_client_config is not None:
392+
config = grpc_client_config.get("config", None)
393+
if config is not None:
394+
type = config.get("type",None)
395+
auth_level = config.get("auth_level",None)
396+
log_level = config.get("log_level", None)
397+
fvs_updated = swsscommon.FieldValuePairs([('type', type),
398+
('auth_level',auth_level ),
399+
('log_level',log_level)])
400+
grpc_config[asic_index].set('config', fvs_updated)
401+
certs = grpc_client_config.get("certs", None)
402+
if certs is not None:
403+
client_crt = certs.get("client_crt", None)
404+
client_key = certs.get("client_key", None)
405+
ca_crt = certs.get("ca_crt", None)
406+
grpc_ssl_credential = certs.get("grpc_ssl_credential",None)
407+
fvs_updated = swsscommon.FieldValuePairs([('client_crt', client_crt),
408+
('client_key', client_key),
409+
('grpc_ssl_credential', grpc_ssl_credential),
410+
('ca_crt',ca_crt)])
411+
grpc_config[asic_index].set('certs', fvs_updated)
412+
372413

373414
def get_grpc_credentials(type, kvp):
374415

375416
root_file = kvp.get("ca_crt", None)
376-
if root_file is not None:
417+
if root_file is not None and os.path.isfile(root_file):
377418
root_cert = open(root_file, 'rb').read()
378419
else:
379420
helper_logger.log_error("grpc credential channel setup no root file in config_db")
380421
return None
381422

382423
if type == "mutual":
383424
cert_file = kvp.get("client_crt", None)
384-
if cert_file is not None:
425+
if cert_file is not None and os.path.isfile(cert_file):
385426
cert_chain = open(cert_file, 'rb').read()
386427
else:
387428
helper_logger.log_error("grpc credential channel setup no cert file for mutual authentication in config_db")
388429
return None
389430

390431
key_file = kvp.get("client_key", None)
391-
if key_file is not None:
432+
if key_file is not None and os.path.isfile(key_file):
392433
key = open(key_file, 'rb').read()
393434
else:
394435
helper_logger.log_error("grpc credential channel setup no key file for mutual authentication in config_db")
@@ -695,6 +736,8 @@ def setup_grpc_channels(stop_event):
695736

696737
if read_side == -1:
697738
read_side = process_loopback_interface_and_get_read_side(loopback_keys)
739+
if os.path.isfile(SECRETS_PATH):
740+
apply_grpc_secrets_configuration(SECRETS_PATH)
698741

699742
helper_logger.log_debug("Y_CABLE_DEBUG:while setting up grpc channels read side = {}".format(read_side))
700743

@@ -1377,6 +1420,8 @@ def init_ports_status_for_y_cable(platform_sfp, platform_chassis, y_cable_presen
13771420

13781421
if read_side == -1:
13791422
read_side = process_loopback_interface_and_get_read_side(loopback_keys)
1423+
if os.path.isfile(SECRETS_PATH):
1424+
apply_grpc_secrets_configuration(SECRETS_PATH)
13801425

13811426
# Init PORT_STATUS table if ports are on Y cable
13821427
logical_port_list = y_cable_platform_sfputil.logical
@@ -1439,6 +1484,8 @@ def change_ports_status_for_y_cable_change_event(port_dict, y_cable_presence, st
14391484

14401485
if read_side == -1:
14411486
read_side = process_loopback_interface_and_get_read_side(loopback_keys)
1487+
if os.path.isfile(SECRETS_PATH):
1488+
apply_grpc_secrets_configuration(SECRETS_PATH)
14421489

14431490

14441491
# Init PORT_STATUS table if ports are on Y cable and an event is received
@@ -1500,6 +1547,7 @@ def delete_ports_status_for_y_cable():
15001547
state_db, config_db, port_tbl, y_cable_tbl = {}, {}, {}, {}
15011548
y_cable_tbl_keys = {}
15021549
static_tbl, mux_tbl = {}, {}
1550+
grpc_config = {}
15031551
namespaces = multi_asic.get_front_end_namespaces()
15041552
for namespace in namespaces:
15051553
asic_id = multi_asic.get_asic_index_from_namespace(namespace)
@@ -1513,6 +1561,14 @@ def delete_ports_status_for_y_cable():
15131561
mux_tbl[asic_id] = swsscommon.Table(
15141562
state_db[asic_id], MUX_CABLE_INFO_TABLE)
15151563
port_tbl[asic_id] = swsscommon.Table(config_db[asic_id], "MUX_CABLE")
1564+
grpc_config[asic_id] = swsscommon.Table(config_db[asic_id], "GRPCCLIENT")
1565+
1566+
1567+
if read_side != -1:
1568+
asic_index = multi_asic.get_asic_index_from_namespace(DEFAULT_NAMESPACE)
1569+
if os.path.isfile(SECRETS_PATH):
1570+
grpc_config[asic_index]._del("config")
1571+
grpc_config[asic_index]._del("certs")
15161572

15171573
# delete PORTS on Y cable table if ports on Y cable
15181574
logical_port_list = y_cable_platform_sfputil.logical

0 commit comments

Comments
 (0)