Service de gestion des certificats gNOI
Utilisez le service gNOI CertificateManagement pour gérer les certificats sur l’élément réseau cible.
Vue d’ensemble
Le service gNOI CertificateManagement du package gère la gnoi.certificate gestion des certificats sur l’élément réseau cible. Le fichier de définition du proto se trouve à https://github.com/openconfig/gnoi/blob/master/cert/cert.proto.
Une infrastructure à clé publique (PKI) prend en charge la distribution et l’identification des clés de chiffrement publiques, ce qui permet aux utilisateurs d’échanger des données en toute sécurité sur des réseaux tels qu’Internet et de vérifier l’identité de l’autre partie. La PKI Junos vous permet de gérer les certificats à clé publique sur les équipements Junos, y compris le téléchargement, la génération et la vérification des certificats. Le service gNOI CertificateManagement définit les opérations de gestion des certificats, qui se fait via l’ICP Junos. Les deux principales opérations sont :
-
Installer : installez un nouveau certificat à l’aide d’un nouvel ID de certificat sur le périphérique réseau cible. Si l’ID de certificat existe déjà, l’opération renvoie une erreur.
-
Rotation : remplacez un certificat existant, qui a déjà un ID de certificat existant, sur le périphérique réseau cible. Si le flux est interrompu ou si l’une des étapes échoue pendant le processus, l’appareil revient au certificat d’origine.
La figure 1 présente le flux de travail pour les Install() opérations et Rotate() . Pour les deux opérations, le client peut générer lui-même la demande de signature de certificat (CSR) ou demander à la cible de générer la CSR. Dans les deux cas, le client transmet la CSR à une autorité de certification (AC) pour demander un certificat numérique. Le client charge ensuite le certificat sur la cible, soit avec un nouvel ID de certificat pour Install() les opérations, soit avec un ID de certificat existant pour Rotate() les opérations. Pour Rotate() les opérations, le client doit également valider les certificats de remplacement et finaliser ou annuler l’opération Rotate() en fonction de la réussite ou de l’échec de la validation. Si le client annule l’opération, le serveur restaure le certificat, la paire de clés et tout bundle d’AC, s’ils sont présents dans la requête.
À partir de la version 23.1R1 de Junos OS Evolved, le Install()Rotate()LoadCertificate() serveur gNOI vérifie le nouveau certificat d’entité finale à l’aide du certificat d’AC correspondant. Ainsi, la PKI du serveur gNOI doit inclure le certificat de l'AC racine qui vérifie le nouveau certificat. Vous pouvez charger le certificat d’AC requis dans le bundle d’AC gNOI ou le charger séparément. Si la vérification échoue, l’appareil n’installe pas le nouveau certificat.
Le serveur gNOI ne prend en charge qu’un seul bundle global de certificats AC pour les services gNOI. Lorsque vous utilisez le service gNOI CertificateManagement pour charger le bundle AC, les instructions suivantes s’appliquent :
-
Le
CertificateManagementservice charge toujours le bundle de certificats d’AC à l’aide de l’identifiantca-profile-groupgnoi-ca-bundleréservé . -
Si vous utilisez le service pour charger le bundle de certificats d’AC
CertificateManagement, l’appareil utilise implicitement l’authentification mutuelle. -
Si le service envoie une demande de chargement d’un
CertificateManagementnouveau bundle de certificats d’AC, le serveur efface les certificats du bundle d’AC précédent de l’appareil et charge les nouveaux. -
Si vous utilisez le
CertificateManagementservice pour charger un bundle de certificats AC et que vous configurez explicitement l’authentification mutuelle dans la configuration de l’appareil, les instructions configurées sont prioritaires.
Ainsi, vous pouvez d’abord configurer l’authentification serveur uniquement sur le serveur gNOI, puis utiliser le Install() RPC pour charger les certificats AC. Lorsque vous utilisez gNOI pour charger le lot initial de certificats d’AC, l’équipement effectue les étapes suivantes :
- Ajoute les certificats AC dans l’ICP Junos.
- Configure automatiquement le bundle de certificats gNOI AC au niveau de la hiérarchie à l’aide
[edit security pki]de l’identifiantca-profile-groupgnoi-ca-bundle. - Commutateurs de l’authentification serveur uniquement à l’authentification mutuelle.
[edit]
security {
pki {
ca-profile gnoi-ca-bundle_1 {
ca-identity gnoi-ca-bundle_1;
}
ca-profile gnoi-ca-bundle_2 {
ca-identity gnoi-ca-bundle_2;
}
ca-profile-group gnoi-ca-bundle {
cert-base-count 2;
}
}
}
Le Rotate() RPC ne prend pas en charge le passage d’un mode d’authentification à l’autre pendant l’opération de rotation. Ainsi, ne prend pas en charge le chargement du bundle de certificats AC sur le serveur gNOI pour la première fois, Rotate() car cela fait passer l’appareil de l’authentification serveur uniquement à l’authentification mutuelle pendant l’opération. Lorsque le mode d’authentification change, le périphérique réseau doit redémarrer la pile gRPC et la connexion est perdue. Si le flux est interrompu, le client ne peut pas finaliser la demande de rotation et l’appareil revient aux certificats qui étaient en place avant le lancement de la Rotate() demande.
L’instruction hot-reloading au niveau de la [edit system services extension-service request-response grpc ssl] hiérarchie ne conserve la session gRPC lors d’une mise à jour de certificat que lorsque le mode d’authentification reste inchangé pendant l’opération. Si le mode d’authentification passe, par exemple, de l’authentification serveur uniquement à l’authentification mutuelle ou vice versa, le client se déconnecte.
RPC pris en charge
Le Tableau 1 présente les RPC de service pris en charge sur les CertificateManagement équipements Junos.
| RPC | Descriptif | Introduit dans la version |
|---|---|---|
CanGenerateCSR() |
Interrogez l’appareil cible pour déterminer s’il peut générer une demande de signature de certificat (CSR) avec le type, la taille et le type de clé spécifiés. Valeurs prises en charge :
Renvoie |
Junos OS Evolved 23.1R1 |
GenerateCSR() |
Générez et renvoyez une demande de signature de certificat (CSR). |
Junos OS Evolved 22.2R1 |
GetCertificates() |
Renvoyer les certificats locaux chargés sur l’appareil cible. |
Junos OS Evolved 22.2R1 |
Install() |
Chargez un nouveau certificat sur l’appareil cible en créant une demande CSR, en générant un certificat basé sur le CSR et en chargeant le certificat à l’aide d’un nouvel ID de certificat. |
Junos OS Evolved 22.2R1 |
LoadCertificate() |
Chargez un certificat signé par une autorité de certification (AC) sur l’équipement cible. |
Junos OS Evolved 22.2R1 |
LoadCertificateAuthorityBundle() |
Chargez un bundle de certificats d’AC sur l’équipement cible. |
Junos OS Evolved 22.2R1 |
RevokeCertificates() |
Révoquez les certificats avec les ID de certificat spécifiés sur l’équipement cible. |
Junos OS Evolved 23.1R1 |
Rotate() |
Remplacez un certificat existant sur l’appareil cible en créant une demande CSR, en générant un certificat basé sur le CSR et en chargeant le certificat à l’aide d’un ID de certificat existant. |
Junos OS Evolved 22.2R1 |
Configuration des équipements réseau
Avant de commencer :
- Configurez les services gRPC sur le périphérique réseau comme décrit dans la section Configurer les services gRPC.
- Configurez le système de gestion du réseau pour prendre en charge les opérations gNOI comme décrit dans Configuration des services gNOI.
Pour les serveurs gNOI configurés au niveau de la hiérarchie, aucune configuration supplémentaire n’est [edit system services http servers] requise.
Pour les serveurs gNOI configurés au niveau de la [edit system services extension-service request-response grpc ssl] hiérarchie, vous devez configurer les use-pki instructions et au hot-reloading même niveau hiérarchique. L’instruction hot-reloading est requise pour maintenir la session gRPC lors de la mise à jour de certificats qui affectent la session. Pour configurer les instructions :
Installation d’un certificat
Vous pouvez utiliser le CertificateManagement service Install() RPC pour charger un nouveau certificat sur l’appareil cible. Lorsque vous installez un nouveau certificat à l’aide de l’opération Install() , vous devez spécifier un nouvel ID de certificat qui n’existe pas déjà sur l’appareil cible. Vous pouvez aussi charger un bundle de certificats d’AC dans le cadre de l’opération Install() .
Dans le cadre de l’opération Install() , l’appareil vérifie le nouveau certificat. Par conséquent, la PKI Junos doit disposer du certificat d’AC racine qui vérifie le nouveau certificat. Vous pouvez charger le certificat d’AC requis dans le cadre de l’opération Install() , ou vous pouvez le charger séparément, avant l’opération, s’il n’est pas déjà dans l’ICP.
Si vous installez un nouveau certificat local qui sera utilisé pour l’authentification de session gRPC, vous devez également mettre à jour la configuration du serveur gRPC sur l’appareil pour utiliser le nouvel ID de certificat.
Exemple : Installation d’un certificat
Dans cet exemple, le serveur gNOI a été initialement configuré avec un certificat local uniquement et n’a pas été configuré pour utiliser l’authentification mutuelle. Le client gNOI utilise le Install() RPC pour charger un nouveau certificat local et un bundle de certificats AC sur l’appareil. Une fois le bundle AC chargé sur le serveur gNOI, le serveur utilise l’authentification mutuelle par défaut. L’offre groupée d’AC comprend le certificat d’AC racine pour le certificat client ainsi que le certificat d’AC racine pour le nouveau certificat de serveur.
Le client exécute l’application gnoi_cert_install_certificate_csr.py Python, qui effectue les opérations suivantes :
- Demande à la cible de générer un CSR.
- Obtient un certificat signé basé sur le CSR.
- Charge le nouveau certificat de serveur, le nouveau certificat d'AC racine du serveur et le certificat d'AC racine du client sur le périphérique réseau cible.
L’application utilise le InstallCertificateRequest message avec les paramètres appropriés pour définir les demandes de génération du CSR et de chargement des certificats. Pour chaque demande, l’application utilise le Install() RPC pour envoyer les demandes à l’équipement réseau.
L’application gnoi_cert_install_certificate_csr.py importe le grpc_channel module pour établir le canal. Le grpc_channel module est décrit dans Configurer les services gNOI. Les arguments de l'application sont stockés dans le args_cert_install_csr.txt fichier. Les dossiers de candidature et d’argumentation sont présentés ici.
gnoi_cert_install_certificate_csr.py
"""gNOI Install Certificate utility."""
from __future__ import print_function
from __future__ import unicode_literals
import argparse
import logging
import re
from getpass import getpass
from subprocess import call
import cert_pb2
import cert_pb2_grpc
from grpc_channel import grpc_authenticate_channel_server_only
def get_args(parser):
parser.add_argument('--server',
dest='server',
type=str,
default='localhost',
help='Server IP or name. Default is localhost.')
parser.add_argument('--port',
dest='port',
nargs='?',
type=int,
default=32767,
help='Server port. Default is 32767')
parser.add_argument('--client_key',
dest='client_key',
type=str,
default='',
help='Full path of the client private key. Default is "".')
parser.add_argument('--client_cert',
dest='client_cert',
type=str,
default='',
help='Full path of the client certificate. Default is "".')
parser.add_argument('--root_ca_cert',
dest='root_ca_cert',
required=True,
type=str,
help='Full path of the Root CA certificate.')
parser.add_argument('--user_id',
dest='user_id',
required=True,
type=str,
help='User ID for RPC call credentials.')
parser.add_argument('--type',
dest='type',
type=int,
default='1',
help='Certificate Type. Default is 1. Valid value is 1 (1 is CT_X509); Invalid value is 0 (0 is CT_UNKNOWN).')
parser.add_argument('--min_key_size',
dest='min_key_size',
type=int,
default='2048',
help='Minimum key size. Default is 2048.')
parser.add_argument('--key_type',
dest='key_type',
type=int,
default='1',
help='Key Type. Default is 1 (KT_RSA); 0 is KT_UNKNOWN.')
parser.add_argument('--common_name',
dest='common_name',
type=str,
default='',
help='CN of the certificate')
parser.add_argument('--country',
dest='country',
type=str,
default='US',
help='Country name')
parser.add_argument('--state',
dest='state',
type=str,
default='CA',
help='State name')
parser.add_argument('--city',
dest='city',
type=str,
default='Sunnyvale',
help='City name')
parser.add_argument('--organization',
dest='organization',
type=str,
default='Acme',
help='Organization name')
parser.add_argument('--organizational_unit',
dest='organizational_unit',
type=str,
default='Test',
help='Organization unit name')
parser.add_argument('--ip_address',
dest='ip_address',
type=str,
default='',
help='IP address on the certificate')
parser.add_argument('--email_id',
dest='email_id',
type=str,
default='',
help='Email id')
parser.add_argument('--certificate_id',
dest='certificate_id',
required=True,
type=str,
help='Certificate id.')
parser.add_argument('--server_cert_private_key',
dest='server_cert_private_key',
type=str,
default='',
help='Server certificate private key')
parser.add_argument('--server_cert_public_key',
dest='server_cert_public_key',
type=str,
default='',
help='Server certificate public key')
parser.add_argument('--server_cert',
dest='server_cert',
type=str,
default='server_cert',
help='Server certificate')
parser.add_argument('--server_root_ca1',
dest='server_root_ca1',
type=str,
default='server_root_ca1',
help='Server Root CA')
parser.add_argument('--server_root_ca2',
dest='server_root_ca2',
type=str,
default='server_root_ca2',
help='Server Root CA')
parser.add_argument('--client_root_ca1',
dest='client_root_ca1',
type=str,
default='client_root_ca1',
help='Client Root CA')
parser.add_argument('--client_root_ca2',
dest='client_root_ca2',
type=str,
default='client_root_ca2',
help='Client Root CA')
parser.add_argument('--client_root_ca3',
dest='client_root_ca3',
type=str,
default='client_root_ca3',
help='Client Root CA')
parser.add_argument('--client_root_ca4',
dest='client_root_ca4',
type=str,
default='client_root_ca4',
help='Client Root CA')
args = parser.parse_args()
return args
def install_cert(channel, metadata, args):
try:
stub = cert_pb2_grpc.CertificateManagementStub(channel)
print("Executing GNOI::CertificateManagement::Install")
# Create request to generate certificate signing request (CSR)
it = []
req = cert_pb2.InstallCertificateRequest()
req.generate_csr.csr_params.type = args.type
req.generate_csr.csr_params.min_key_size = args.min_key_size
req.generate_csr.csr_params.key_type = args.key_type
req.generate_csr.csr_params.common_name = args.common_name
req.generate_csr.csr_params.country = args.country
req.generate_csr.csr_params.state = args.state
req.generate_csr.csr_params.city = args.city
req.generate_csr.csr_params.organization = args.organization
req.generate_csr.csr_params.organizational_unit = args.organizational_unit
req.generate_csr.csr_params.ip_address = args.ip_address
req.generate_csr.csr_params.email_id = args.email_id
req.generate_csr.certificate_id = args.certificate_id
it.append(req)
# Send request to generate CSR
for csr_rsp in stub.Install(iter(it), metadata=metadata, timeout=180):
logging.info(csr_rsp)
# Write CSR to a file
with open('/home/lab/certs/server_temp.csr', "wb") as file:
file.write(csr_rsp.generated_csr.csr.csr)
# If client connects to server IP address
# update openssl.cnf template to include subjectAltName IP extension
with open('/etc/pki/certs/openssl.cnf', 'r') as fd:
data = fd.read()
data1 = re.sub(r'(subjectAltName=IP:).*',
r'\g<1>'+args.ip_address, data)
with open('/home/lab/certs/openssl_temp.cnf', 'w') as fd:
fd.write(data1)
# Generate certificate with v3 extensions
cmd = "openssl x509 -req -days 365 -in /home/lab/certs/server_temp.csr -CA /etc/pki/certs/serverRootCA.crt -CAkey /etc/pki/certs/serverRootCA.key -CAcreateserial -out /home/lab/certs/server_temp.crt -extensions v3_sign -extfile /home/lab/certs/openssl_temp.cnf -sha384"
decrypted = call(cmd, shell=True)
# Create request to install node certificate and CA certificates
print("\nExecuting GNOI::CertificateManagement::Install")
it = []
req = cert_pb2.InstallCertificateRequest()
# Import certificate and add to request
cert_data = bytearray(b'')
with open("/home/lab/certs/server_temp.crt", "rb") as file:
cert_data = file.read()
req.load_certificate.certificate.type = args.type
req.load_certificate.certificate_id = args.certificate_id
req.load_certificate.certificate.certificate = cert_data
# Add client and server CA certificates to request
ca1 = req.load_certificate.ca_certificates.add()
ca1.type = args.type
ca1.certificate = open(args.client_root_ca1, 'rb').read()
ca2 = req.load_certificate.ca_certificates.add()
ca2.type = args.type
ca2.certificate = open(args.server_root_ca1, 'rb').read()
it.append(req)
# Send request to install node certificate and CA bundle
for rsp in stub.Install(iter(it), metadata=metadata, timeout=180):
logging.info("Installing certificates: %s", rsp)
print("Install complete.")
except Exception as e:
logging.error('Certificate install error: %s', e)
print(e)
def main():
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
args = get_args(parser)
grpc_server_password = getpass("gRPC server password for executing RPCs: ")
metadata = [('username', args.user_id),
('password', grpc_server_password)]
try:
# Establish grpc channel to network device
channel = grpc_authenticate_channel_server_only(
args.server, args.port, args.root_ca_cert)
install_cert(channel, metadata, args)
except Exception as e:
logging.error('Received error: %s', e)
print(e)
if __name__ == '__main__':
logging.basicConfig(filename='gnoi-testing.log',
format='%(asctime)s %(levelname)-8s %(message)s',
level=logging.INFO,
datefmt='%Y-%m-%d %H:%M:%S')
main()
args_cert_install_csr.txt
--server=10.53.52.169 --port=32767 --root_ca_cert=/etc/pki/certs/serverRootCA.crt --user_id=gnoi-user --type=1 --min_key_size=2048 --key_type=1 --common_name=gnoi-server.example.com --country=US --state=CA --city=Sunnyvale --organization=Acme --organizational_unit=testing --ip_address=10.53.52.169 --email_id=test@example.com --certificate_id=gnoi-server1 --client_root_ca1=/etc/pki/certs/clientRootCA.crt --server_root_ca1=/etc/pki/certs/serverRootCA1.crt
Exécuter l’application
Lorsque le client exécute l’application, celle-ci demande le CSR, obtient le certificat signé et charge le nouveau certificat de serveur et les certificats AC sur le périphérique réseau cible.
lab@gnoi-client:~/src/gnoi/proto$ python3 gnoi_cert_install_certificate_csr.py @args_cert_install_csr.txt gRPC server password for executing RPCs: Creating channel Executing GNOI::CertificateManagement::Install Signature ok subject=CN = gnoi-server.example.com, C = US, ST = CA, O = Acme, OU = testing Getting CA Private Key Executing GNOI::CertificateManagement::Install Install complete.
Après avoir installé le nouveau certificat de serveur, vous devez configurer le serveur pour qu’il utilise cet ID de certificat pour l’authentification de session gRPC. Mettez à jour l’instruction local-certificate pour votre configuration de serveur spécifique, qui peut être configurée à l’un des niveaux hiérarchiques suivants :
-
[modifier services système extension-service-demande-réponse grpc ssl]
-
[modifier : services système, serveurs http, serveur name tls]
Par exemple :
user@gnoi-server> show configuration system services extension-service request-response grpc ssl port 32767; local-certificate gnoi-server1; hot-reloading; use-pki;
De plus, comme l’opération a chargé de Install() nouveaux certificats d’AC, l’appareil utilise implicitement l’authentification mutuelle. Par conséquent, toutes les sessions gRPC suivantes doivent inclure le certificat et la clé du client lors de l'établissement du canal.
Si vous exécutez l’application et fournissez un ID de certificat qui existe déjà sur le serveur, l’application renvoie une ALREADY_EXISTS erreur, car l’opération Install() nécessite un nouvel ID de certificat.
lab@gnoi-client:~/src/gnoi/proto$ python3 gnoi_cert_install_certificate_csr.py @args_cert_install_csr.txt
gRPC server password for executing RPCs:
Creating channel
Executing GNOI::CertificateManagement::Install
Signature ok
subject=CN = gnoi-server.example.com, C = US, ST = CA, O = Acme, OU = testing
Getting CA Private Key
Executing GNOI::CertificateManagement::Install
<_MultiThreadedRendezvous of RPC that terminated with:
status = StatusCode.ALREADY_EXISTS
details = ""
debug_error_string = "{"created":"@1652241881.676147097","description":"Error received from peer ipv4:10.53.52.169:32767","file":"src/core/lib/surface/call.cc","file_line":903,"grpc_message":"","grpc_status":6}"
Rotation d’un certificat
Vous pouvez utiliser le CertificateManagement service Rotate() RPC pour remplacer un certificat existant sur l’appareil cible. Lorsque vous remplacez un certificat existant à l’aide de l’opération Rotate() , vous devez charger le certificat à l’aide de l’ID de certificat qui existe déjà sur l’appareil cible. Vous pouvez également remplacer le lot de certificats gNOI AC existant dans le cadre de l’opération Rotate() .
L’opération Rotate() est similaire à l’opération Install() , sauf qu’elle Rotate() remplace un certificat existant au lieu d’installer un nouveau certificat. En outre, le client doit valider le fonctionnement du certificat mis à jour, puis finaliser ou annuler la Rotate() demande en fonction de la réussite ou de l’échec de la validation du certificat.
Dans le cadre de l’opération Rotate() , l’appareil vérifie le nouveau certificat. Par conséquent, la PKI Junos doit disposer du certificat d’AC racine qui vérifie le nouveau certificat. Vous pouvez charger le certificat d’AC requis dans le cadre de l’opération Rotate() , ou vous pouvez le charger séparément, avant l’opération, s’il n’est pas déjà dans l’ICP.
Exemple : rotation d’un certificat
Dans cet exemple, le client exécute l’application gnoi_cert_rotate_certificate_csr.py Python, qui effectue les opérations suivantes :
- Demande à la cible de générer un CSR.
- Obtient un certificat signé basé sur le CSR
- Remplace le certificat de nœud et l’offre groupée d’AC gNOI sur l’équipement réseau cible.
- Valide le nouveau certificat.
- Finalise l’opération
Rotate.
L’application utilise le RotateCertificateRequest message avec les paramètres appropriés pour définir les demandes de génération du CSR et de chargement du bundle de certificats et d’AC. Pour chaque demande, l’application utilise le Rotate() RPC pour envoyer la demande à l’équipement réseau. Pour permettre à l’équipement cible de vérifier le nouveau certificat de nœud, l’application remplace le bundle d’AC existant par un nouveau bundle d’AC. L’offre groupée comprend à la fois le certificat d’AC client et le certificat d’AC requis pour vérifier le certificat de nœud.
L’application valide le fonctionnement du nouveau certificat en créant une nouvelle session gRPC avec le périphérique réseau et en exécutant un RPC simple Time() , bien que vous puissiez tester l’authentification de la session avec n’importe quel RPC. L’application finalise la demande de rotation si la session est établie avec succès et annule la demande de rotation si l’authentification de la session échoue.
L’application gnoi_cert_rotate_certificate_csr.py importe le grpc_channel module pour établir le canal. Le grpc_channel module est décrit dans Configurer les services gNOI. Les arguments de l'application sont stockés dans le args_cert_rotate_csr.txt fichier. Les dossiers de candidature et d’argumentation sont présentés ici.
gnoi_cert_rotate_certificate_csr.py
"""gNOI Rotate Certificate utility."""
from __future__ import print_function
from __future__ import unicode_literals
import argparse
import logging
import time
import re
import grpc
from getpass import getpass
from subprocess import call
import cert_pb2
import cert_pb2_grpc
import system_pb2
import system_pb2_grpc
from grpc_channel import grpc_authenticate_channel_mutual
def get_args(parser):
parser.add_argument('--server',
dest='server',
type=str,
default='localhost',
help='Server IP or name. Default is localhost.')
parser.add_argument('--port',
dest='port',
nargs='?',
type=int,
default=32767,
help='Server port. Default is 32767')
parser.add_argument('--client_key',
dest='client_key',
type=str,
default='',
help='Full path of the client private key. Default is "".')
parser.add_argument('--client_cert',
dest='client_cert',
type=str,
default='',
help='Full path of the client certificate. Default is "".')
parser.add_argument('--root_ca_cert',
dest='root_ca_cert',
required=True,
type=str,
help='Full path of the Root CA certificate.')
parser.add_argument('--user_id',
dest='user_id',
required=True,
type=str,
help='User ID for RPC call credentials.')
parser.add_argument('--type',
dest='type',
type=int,
default='1',
help='Certificate Type. Default is 1. Valid value is 1 (1 is CT_X509); Invalid value is 0 (0 is CT_UNKNOWN).')
parser.add_argument('--min_key_size',
dest='min_key_size',
type=int,
default='2048',
help='Minimum key size. Default is 2048.')
parser.add_argument('--key_type',
dest='key_type',
type=int,
default='1',
help='Key Type. Default is 1 (KT_RSA); 0 is KT_UNKNOWN.')
parser.add_argument('--common_name',
dest='common_name',
type=str,
default='',
help='CN of the certificate')
parser.add_argument('--country',
dest='country',
type=str,
default='US',
help='Country name')
parser.add_argument('--state',
dest='state',
type=str,
default='CA',
help='State name')
parser.add_argument('--city',
dest='city',
type=str,
default='Sunnyvale',
help='City name')
parser.add_argument('--organization',
dest='organization',
type=str,
default='Acme',
help='Organization name')
parser.add_argument('--organizational_unit',
dest='organizational_unit',
type=str,
default='Test',
help='Organization unit name')
parser.add_argument('--ip_address',
dest='ip_address',
type=str,
default='',
help='IP address on the certificate')
parser.add_argument('--email_id',
dest='email_id',
type=str,
default='',
help='Email id')
parser.add_argument('--certificate_id',
dest='certificate_id',
required=True,
type=str,
help='Certificate id.')
parser.add_argument('--server_cert_private_key',
dest='server_cert_private_key',
type=str,
default='',
help='Server certificate private key')
parser.add_argument('--server_cert_public_key',
dest='server_cert_public_key',
type=str,
default='',
help='Server certificate public key')
parser.add_argument('--server_cert',
dest='server_cert',
type=str,
default='server_cert',
help='Server certificate')
parser.add_argument('--server_root_ca1',
dest='server_root_ca1',
type=str,
default='server_root_ca1',
help='Server Root CA')
parser.add_argument('--server_root_ca2',
dest='server_root_ca2',
type=str,
default='server_root_ca2',
help='Server Root CA')
parser.add_argument('--client_root_ca1',
dest='client_root_ca1',
type=str,
default='client_root_ca1',
help='Client Root CA')
parser.add_argument('--client_root_ca2',
dest='client_root_ca2',
type=str,
default='client_root_ca2',
help='Client Root CA')
parser.add_argument('--client_root_ca3',
dest='client_root_ca3',
type=str,
default='client_root_ca3',
help='Client Root CA')
parser.add_argument('--client_root_ca4',
dest='client_root_ca4',
type=str,
default='client_root_ca4',
help='Client Root CA')
parser.add_argument("--client_key_test",
dest='client_key_test',
type=str,
default='',
help='Full path of the test client private key. Default ""')
parser.add_argument("--client_cert_test",
dest='client_cert_test',
type=str,
default='',
help='Full path of the test client certificate. Default ""')
args = parser.parse_args()
return args
def rotate_cert(channel, metadata, args):
try:
result = ''
stub = cert_pb2_grpc.CertificateManagementStub(channel)
print("Executing GNOI::CertificateManagement::Rotate")
# Create request to generate certificate signing request (CSR)
it = []
req = cert_pb2.RotateCertificateRequest()
req.generate_csr.csr_params.type = args.type
req.generate_csr.csr_params.min_key_size = args.min_key_size
req.generate_csr.csr_params.key_type = args.key_type
req.generate_csr.csr_params.common_name = args.common_name
req.generate_csr.csr_params.country = args.country
req.generate_csr.csr_params.state = args.state
req.generate_csr.csr_params.city = args.city
req.generate_csr.csr_params.organization = args.organization
req.generate_csr.csr_params.organizational_unit = args.organizational_unit
req.generate_csr.csr_params.ip_address = args.ip_address
req.generate_csr.csr_params.email_id = args.email_id
req.generate_csr.certificate_id = args.certificate_id
it.append(req)
# Send request to generate CSR
print('Sending request for CSR')
for csr_rsp in stub.Rotate(iter(it), metadata=metadata, timeout=30):
logging.info(csr_rsp)
# Write CSR to a file
with open('/home/lab/certs/server_temp.csr', "wb") as file:
file.write(csr_rsp.generated_csr.csr.csr)
# If client connects to server IP address
# update openssl.cnf template to include subjectAltName IP extension
with open('/etc/pki/certs/openssl.cnf', 'r') as fd:
data = fd.read()
data1 = re.sub(r'(subjectAltName=IP:).*',
r'\g<1>'+args.ip_address, data)
with open('/home/lab/certs/openssl_temp.cnf', 'w') as fd:
fd.write(data1)
# Generate certificate with v3 extensions
cmd = "openssl x509 -req -days 365 -in /home/lab/certs/server_temp.csr -CA /etc/pki/certs/serverRootCA.crt -CAkey /etc/pki/certs/serverRootCA.key -CAcreateserial -out /home/lab/certs/server_temp.crt -extensions v3_sign -extfile /home/lab/certs/openssl_temp.cnf -sha384"
decrypted = call(cmd, shell=True)
# Create request to rotate node certificate and CA certificates
print("\nExecuting GNOI::CertificateManagement::Rotate")
it = []
req = cert_pb2.RotateCertificateRequest()
# Import certificate and add to request
with open("/home/lab/certs/server_temp.crt", "rb") as file:
cert_data = file.read()
req.load_certificate.certificate.type = args.type
req.load_certificate.certificate.certificate = cert_data
req.load_certificate.certificate_id = args.certificate_id
# Add client and server CA certificates to request
ca1 = req.load_certificate.ca_certificates.add()
ca1.type = args.type
ca1.certificate = open(args.client_root_ca1, 'rb').read()
ca2 = req.load_certificate.ca_certificates.add()
ca2.type = args.type
ca2.certificate = open(args.server_root_ca1, 'rb').read()
it.append(req)
# Send request to replace node certificate and CA bundle
for rsp in stub.Rotate(iter(it), metadata=metadata, timeout=60):
logging.info("Rotating certificates. %s", rsp)
# Validate certificates
print("Validating certificates")
time.sleep(5)
validate_rc = True
try:
validate_channel = grpc_authenticate_channel_mutual(
args.server, args.port, args.server_root_ca1, args.client_key_test,
args.client_cert_test)
validate_stub = system_pb2_grpc.SystemStub(validate_channel)
validate_rsp = validate_stub.Time(
request=system_pb2.TimeRequest(), metadata=metadata, timeout=60)
except grpc.RpcError as e:
print("Validation failed with error:", e)
validate_rc = False
pass
if validate_rc:
print("Finalizing certificate rotation.")
it = []
req = cert_pb2.RotateCertificateRequest()
req.finalize_rotation.SetInParent()
it.append(req)
for rsp in stub.Rotate(iter(it), metadata=metadata, timeout=30):
logging.info("Finalizing rotate. %s", rsp)
logging.info(
"Certificate validation succeeded. Certificate rotation finalized.")
result = "Certificate rotation finalized."
else:
print("Rolling back certificates.")
logging.info(
"Certificate validation failed. Rolling back to original certificates.")
rsp.cancel()
except Exception as e:
logging.error('Certificate rotate error: %s', e)
print(e)
else:
return result
def main():
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
args = get_args(parser)
grpc_server_password = getpass("gRPC server password for executing RPCs: ")
metadata = [('username', args.user_id),
('password', grpc_server_password)]
try:
# Establish grpc channel to network device
channel = grpc_authenticate_channel_mutual(
args.server, args.port, args.root_ca_cert, args.client_key, args.client_cert)
response = rotate_cert(channel, metadata, args)
print(response)
except Exception as e:
logging.error('Error: %s', e)
print(e)
if __name__ == '__main__':
logging.basicConfig(filename='gnoi-testing.log',
format='%(asctime)s %(levelname)-8s %(message)s',
level=logging.INFO,
datefmt='%Y-%m-%d %H:%M:%S')
main()
args_cert_rotate_csr.txt
--server=10.53.52.169 --port=32767 --root_ca_cert=/etc/pki/certs/serverRootCA.crt --client_key=/home/lab/certs/client.key --client_cert=/home/lab/certs/client.crt --user_id=gnoi-user --type=1 --min_key_size=2048 --key_type=1 --common_name=gnoi-server.example.com --country=US --state=CA --city=Sunnyvale --organization=Acme --organizational_unit=testing --ip_address=10.53.52.169 --email_id=test@example.com --certificate_id=gnoi-server --client_root_ca1=/etc/pki/certs/clientRootCA.crt --server_root_ca1=/etc/pki/certs/serverRootCA.crt --client_key_test=/home/lab/certs/client.key --client_cert_test=/home/lab/certs/client.crt
Il est important de noter que l root_ca_cert 'argument correspond au certificat d'AC racine du serveur requis pour les informations d'identification du canal initial. L server_root_ca1 'argument est le certificat d'AC racine correspondant au nouveau certificat du serveur. La PKI Junos doit disposer du nouveau certificat d’AC racine afin de vérifier le nouveau certificat local pendant l’opération Rotate() . De plus, les informations d’identification du canal pour la session gRPC qui valide le nouveau certificat utilisent ce certificat AC racine. Bien que cet exemple utilise le même certificat de AC racine pour le nouveau et l’ancien certificat de serveur, ceux-ci peuvent différer dans un autre cas.
Exécuter l’application
Lorsque le client exécute l’application, celle-ci demande le CSR, récupère le certificat signé et charge le certificat de remplacement et le bundle AC sur l’équipement réseau cible. L’application valide ensuite le certificat de remplacement avec une nouvelle session gRPC qui exécute un RPC simple Time() . Une fois la validation réussie, le client finalise la demande de rotation.
lab@gnoi-client:~/src/gnoi/proto$ python3 gnoi_cert_rotate_certificate_csr.py @args_cert_rotate_csr.txt gRPC server password for executing RPCs: Creating channel Executing GNOI::CertificateManagement::Rotate Sending request for CSR Signature ok subject=CN = gnoi-server.example.com, C = US, ST = CA, O = Acme, OU = testing Getting CA Private Key Executing GNOI::CertificateManagement::Rotate Validating certificates Creating channel Finalizing certificate rotation. Certificate rotation finalized.
Révoquer un certificat
Un client gNOI peut utiliser le RevokeCertificates() RPC pour supprimer un ou plusieurs certificats de l’appareil cible. Le client inclut un RevokeCertificatesRequest message avec la liste des ID de certificat à révoquer.
Lorsque le serveur gNOI reçoit la RevokeCertificates() demande, il traite chaque ID de certificat de la liste comme suit :
-
Si le certificat est présent et que la révocation est réussie, l’équipement supprime le certificat du système de fichiers et de l’ICP Junos et ajoute l’ID du certificat à la liste des certificats révoqués avec succès.
-
Si le certificat est présent et que la révocation échoue, l’appareil inclut l’ID de certificat et la raison de l’échec dans la liste d’erreurs de révocation de certificat.
-
Si le certificat n’est pas présent, l’appareil considère que l’opération de révocation a réussi et ajoute l’ID de certificat à la liste des certificats révoqués avec succès.
Si la demande révoque le certificat utilisé pour la session en cours, celle-ci n’est pas affectée.
Après avoir traité la requête, le serveur gNOI renvoie un RevokeCertificatesResponse message qui inclut :
-
Liste des ID de certificat révoqués avec succès.
-
Liste des erreurs de révocation contenant l’ID du certificat et la raison de l’échec.
Exemple : Révoquer un certificat
Dans cet exemple, le client exécute l’application gnoi_cert_revoke_certificates.py Python, qui révoque deux certificats sur le serveur. Le premier ID de certificat est un identifiant valide sur l’appareil. Le deuxième ID de certificat est un identifiant qui n’existe pas sur l’appareil.
L’application utilise le RevokeCertificatesRequest message avec les paramètres appropriés pour définir la demande. L’application envoie le RevokeCertificates() RPC au périphérique réseau pour effectuer l’opération.
L’application gnoi_cert_revoke_certificates.py importe le grpc_channel module pour établir le canal. Le grpc_channel module est décrit dans Configurer les services gNOI. Les arguments de l'application sont stockés dans le args_cert_revoke_certificates.txt fichier. Les dossiers de candidature et d’argumentation sont présentés ici.
gnoi_cert_revoke_certificates.py
"""gNOI Revoke Certificates utility."""
from __future__ import print_function
from __future__ import unicode_literals
import argparse
import logging
from getpass import getpass
import cert_pb2
import cert_pb2_grpc
from grpc_channel import grpc_authenticate_channel_mutual
def get_args(parser):
parser.add_argument('--server',
dest='server',
type=str,
default='localhost',
help='Server IP or name. Default is localhost.')
parser.add_argument('--port',
dest='port',
nargs='?',
type=int,
default=32767,
help='Server port. Default is 32767')
parser.add_argument('--client_key',
dest='client_key',
type=str,
default='',
help='Full path of the client private key. Default is "".')
parser.add_argument('--client_cert',
dest='client_cert',
type=str,
default='',
help='Full path of the client certificate. Default is "".')
parser.add_argument('--root_ca_cert',
dest='root_ca_cert',
required=True,
type=str,
help='Full path of the Root CA certificate.')
parser.add_argument('--user_id',
dest='user_id',
required=True,
type=str,
help='User ID for RPC call credentials.')
parser.add_argument('--certificate_id1',
dest='certificate_id1',
required=True,
type=str,
help='Certificate id.')
parser.add_argument('--certificate_id2',
dest='certificate_id2',
type=str,
help='Certificate id.')
args = parser.parse_args()
return args
def revoke_cert(channel, metadata, args):
try:
stub = cert_pb2_grpc.CertificateManagementStub(channel)
print("Executing GNOI::CertificateManagement::RevokeCertificates")
# Create request to revoke certificates
req = cert_pb2.RevokeCertificatesRequest()
req.certificate_id.append(args.certificate_id1)
req.certificate_id.append(args.certificate_id2)
# Send request to revoke certificates
logging.info("Sending RevokeCertificates request.")
rsp = stub.RevokeCertificates(req, metadata=metadata, timeout=60)
logging.info(rsp)
print("rsp:\n%s" %rsp)
except Exception as e:
logging.error('Error: %s', e)
print(e)
def main():
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
args = get_args(parser)
grpc_server_password = getpass("gRPC server password for executing RPCs: ")
metadata = [('username', args.user_id),
('password', grpc_server_password)]
try:
# Establish grpc channel to network device
channel = grpc_authenticate_channel_mutual(
args.server, args.port, args.root_ca_cert, args.client_key, args.client_cert)
revoke_cert(channel, metadata, args)
except Exception as e:
logging.error('Received error: %s', e)
print(e)
if __name__ == '__main__':
logging.basicConfig(filename='gnoi-testing.log',
format='%(asctime)s %(levelname)-8s %(message)s',
level=logging.INFO,
datefmt='%Y-%m-%d %H:%M:%S')
main()
args_cert_revoke_certificates.txt
--server=10.53.52.169 --port=32767 --root_ca_cert=/etc/pki/certs/serverRootCA.crt --client_key=/home/lab/certs/client.key --client_cert=/home/lab/certs/client.crt --user_id=gnoi-user --certificate_id1=gnoi-server --certificate_id2=id-does-not-exist
Exécuter l’application
Lorsque le client exécute l’application, celle-ci demande à l’appareil cible de révoquer les certificats spécifiés. L’appareil renvoie une liste des certificats révoqués avec succès et des erreurs. L’appareil considère que l’opération a réussi à la fois pour l’ID de certificat valide et pour l’ID de certificat qui n’existe pas actuellement sur l’appareil.
lab@gnoi-client:~/src/gnoi/proto$ python3 gnoi_cert_revoke_certificates.py @args_cert_revoke_certificates.txt gRPC server password for executing RPCs: Creating channel Executing GNOI::CertificateManagement::RevokeCertificates rsp: revoked_certificate_id: "gnoi-server" revoked_certificate_id: "id-does-not-exist"
Tableau de l’historique des modifications
La prise en charge des fonctionnalités est déterminée par la plateforme et la version que vous utilisez. Utilisez l’explorateur de fonctionnalités pour déterminer si une fonctionnalité est prise en charge sur votre plateforme.
Rotate()les
Install()et les opérations vérifient
LoadCertificate() le nouveau certificat dans le cadre de l’opération.