Last active
January 27, 2025 13:44
-
-
Save german/1a0ff1a9710237f48315fa0978642bf6 to your computer and use it in GitHub Desktop.
Revisions
-
german renamed this gist
Jan 27, 2025 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
german created this gist
Jan 27, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,209 @@ # lib/tasks/stripe_key_rotation.rake require 'stripe' require 'aws-sdk-secretsmanager' namespace :stripe do desc 'Automate Stripe API key rotation process' task rotate_keys: :environment do class StripeKeyRotator def initialize @secrets = Aws::SecretsManager::Client.new( region: ENV['AWS_REGION'], access_key_id: ENV['AWS_ACCESS_KEY_ID'], secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'] ) @slack_notifier = Slack::Notifier.new(ENV['SLACK_WEBHOOK_URL']) @rotation_logger = Logger.new(Rails.root.join('log', 'key_rotation.log')) end def rotate begin rotation_start = Time.current @rotation_logger.info("Starting API key rotation at #{rotation_start}") # Step 1: Create new key in Stripe new_key = create_new_stripe_key # Step 2: Verify new key works verify_new_key(new_key) # Step 3: Store new key in AWS Secrets Manager store_new_key(new_key) # Step 4: Update application configuration update_application_config(new_key) # Step 5: Monitor for errors monitor_key_transition(new_key) # Step 6: Revoke old key if everything is stable revoke_old_key notify_success rescue StandardError => e handle_rotation_error(e) end end private def create_new_stripe_key @rotation_logger.info("Creating new Stripe API key") # Note: This is a placeholder as Stripe doesn't have a direct API for key creation # In practice, you'll need to create the key manually in Stripe Dashboard # and store it securely for the rotation process # Simulate key creation for demonstration new_key = "sk_test_#{SecureRandom.hex(24)}" @rotation_logger.info("New key created successfully") new_key end def verify_new_key(new_key) @rotation_logger.info("Verifying new key functionality") Stripe.api_key = new_key # Perform test API call Stripe::Customer.list(limit: 1) @rotation_logger.info("New key verified successfully") end def store_new_key(new_key) @rotation_logger.info("Storing new key in AWS Secrets Manager") @secrets.put_secret_value( secret_id: 'stripe/api_key', secret_string: new_key ) @rotation_logger.info("New key stored in AWS Secrets Manager") end def update_application_config(new_key) @rotation_logger.info("Updating application configuration") # Update credentials in Rails credentials system("EDITOR='echo #{new_key} >' rails credentials:edit") # Reload configuration in running application Rails.application.credentials.reload @rotation_logger.info("Application configuration updated") end def monitor_key_transition(new_key) @rotation_logger.info("Monitoring key transition") monitoring_period = 1.hour start_time = Time.current error_threshold = 5 error_count = 0 while Time.current - start_time < monitoring_period begin # Monitor API calls and error rates error_rate = check_error_rate if error_rate > error_threshold error_count += 1 if error_count >= 3 raise "High error rate detected during transition" end end sleep 300 # Check every 5 minutes rescue => e @rotation_logger.error("Monitoring error: #{e.message}") raise e if error_count >= 3 end end @rotation_logger.info("Key transition monitoring completed successfully") end def check_error_rate # Implement your error rate checking logic here # This could involve checking your error tracking service # or monitoring Stripe API response codes # Example implementation using Rails cache errors = Rails.cache.read('stripe_api_errors') || 0 total_calls = Rails.cache.read('stripe_api_calls') || 1 (errors.to_f / total_calls) * 100 end def revoke_old_key @rotation_logger.info("Revoking old API key") old_key = Rails.application.credentials.stripe[:old_api_key] # Note: Stripe doesn't provide direct API for key revocation # This would typically be done manually in the Stripe Dashboard # Here we're just logging the action @rotation_logger.info("Old key revoked successfully") end def notify_success message = <<~MSG 🔄 Stripe API Key Rotation Completed Successfully Time: #{Time.current} Environment: #{Rails.env} Status: Success Next rotation scheduled: #{90.days.from_now} MSG @slack_notifier.ping(message) @rotation_logger.info("Key rotation completed successfully") end def handle_rotation_error(error) error_message = <<~MSG ❌ Stripe API Key Rotation Failed Time: #{Time.current} Environment: #{Rails.env} Error: #{error.message} Backtrace: #{error.backtrace.first(5).join("\n")} MSG @slack_notifier.ping(error_message) @rotation_logger.error("Key rotation failed: #{error.message}") # Trigger rollback if necessary rollback_rotation raise error end def rollback_rotation @rotation_logger.info("Initiating rollback procedure") # Implement your rollback logic here # This could involve restoring the old key from backup # and reverting application configuration end end # Execute the rotation StripeKeyRotator.new.rotate end end # config/initializers/stripe_monitoring.rb module StripeMonitoring class ApiCallMonitor def self.track_request Rails.cache.increment('stripe_api_calls') end def self.track_error Rails.cache.increment('stripe_api_errors') end end end # config/schedule.rb (if using whenever gem) every 90.days do rake "stripe:rotate_keys" end